| Index: cc/scheduler/begin_frame_source.cc
|
| diff --git a/cc/scheduler/begin_frame_source.cc b/cc/scheduler/begin_frame_source.cc
|
| index 30916948cec360b751b158e69316c4e6617f8b3b..5d586f7061695c611d6b290c3e1a1dcbf0c09456 100644
|
| --- a/cc/scheduler/begin_frame_source.cc
|
| +++ b/cc/scheduler/begin_frame_source.cc
|
| @@ -6,10 +6,13 @@
|
|
|
| #include <stddef.h>
|
|
|
| +#include "base/atomic_sequence_num.h"
|
| #include "base/auto_reset.h"
|
| #include "base/location.h"
|
| #include "base/logging.h"
|
| #include "base/memory/ptr_util.h"
|
| +#include "base/process/process_handle.h"
|
| +#include "base/stl_util.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/stringprintf.h"
|
| #include "base/trace_event/trace_event.h"
|
| @@ -25,16 +28,22 @@ namespace {
|
| static const double kDoubleTickDivisor = 2.0;
|
| }
|
|
|
| -// BeginFrameObserverBase -----------------------------------------------
|
| +// BeginFrameObserverBase -------------------------------------------------
|
| BeginFrameObserverBase::BeginFrameObserverBase()
|
| - : last_begin_frame_args_(), dropped_begin_frame_args_(0) {
|
| -}
|
| + : last_begin_frame_args_(), dropped_begin_frame_args_(0) {}
|
|
|
| const BeginFrameArgs& BeginFrameObserverBase::LastUsedBeginFrameArgs() const {
|
| return last_begin_frame_args_;
|
| }
|
| +
|
| void BeginFrameObserverBase::OnBeginFrame(const BeginFrameArgs& args) {
|
| - DCHECK(args.IsValid());
|
| + DCHECK(args.IsValid()) << "args: " << BeginFrameArgs::TypeToString(args.type)
|
| + << " " << args.source_id << " " << args.sequence_number
|
| + << " " << args.frame_time.ToInternalValue() << " "
|
| + << args.interval.ToInternalValue() << " "
|
| + << args.deadline.ToInternalValue();
|
| + DCHECK(args.sequence_number > last_begin_frame_args_.sequence_number ||
|
| + args.source_id != last_begin_frame_args_.source_id);
|
| DCHECK(args.frame_time >= last_begin_frame_args_.frame_time);
|
| bool used = OnBeginFrameDerivedImpl(args);
|
| if (used) {
|
| @@ -44,17 +53,44 @@ void BeginFrameObserverBase::OnBeginFrame(const BeginFrameArgs& args) {
|
| }
|
| }
|
|
|
| +// BeginFrameSource -------------------------------------------------------
|
| +namespace {
|
| +static base::StaticAtomicSequenceNumber next_source_id_;
|
| +
|
| +uint64_t CreateSourceId() {
|
| + // Create a FNV hash from the process id for XORing.
|
| + // See http://isthe.com/chongo/tech/comp/fnv/ for algorithm details.
|
| + const uint64_t kOffsetBasis = 14695981039346656037ull;
|
| + const uint64_t kFnvPrime = 1099511628211ull;
|
| + const uint64_t pid = static_cast<uint64_t>(base::GetUniqueIdForProcess());
|
| + const uint64_t process_id_hash = (kOffsetBasis ^ pid) * kFnvPrime;
|
| +
|
| + const uint64_t source_id = static_cast<uint64_t>(next_source_id_.GetNext());
|
| + // Make source id unlikely to collide with other processes.
|
| + return source_id ^ process_id_hash;
|
| +}
|
| +} // namespace
|
| +
|
| +BeginFrameSource::BeginFrameSource() : source_id_(CreateSourceId()) {}
|
| +
|
| +uint64_t BeginFrameSource::source_id() const {
|
| + return source_id_;
|
| +}
|
| +
|
| +// StubBeginFrameSource ---------------------------------------------------
|
| bool StubBeginFrameSource::IsThrottled() const {
|
| return true;
|
| }
|
|
|
| -// SyntheticBeginFrameSource ---------------------------------------------
|
| +// SyntheticBeginFrameSource ----------------------------------------------
|
| SyntheticBeginFrameSource::~SyntheticBeginFrameSource() = default;
|
|
|
| -// BackToBackBeginFrameSource --------------------------------------------
|
| +// BackToBackBeginFrameSource ---------------------------------------------
|
| BackToBackBeginFrameSource::BackToBackBeginFrameSource(
|
| std::unique_ptr<DelayBasedTimeSource> time_source)
|
| - : time_source_(std::move(time_source)), weak_factory_(this) {
|
| + : time_source_(std::move(time_source)),
|
| + next_sequence_number_(1),
|
| + weak_factory_(this) {
|
| time_source_->SetClient(this);
|
| // The time_source_ ticks immediately, so we SetActive(true) for a single
|
| // tick when we need it, and keep it as SetActive(false) otherwise.
|
| @@ -77,13 +113,13 @@ void BackToBackBeginFrameSource::RemoveObserver(BeginFrameObserver* obs) {
|
| DCHECK(observers_.find(obs) != observers_.end());
|
| observers_.erase(obs);
|
| pending_begin_frame_observers_.erase(obs);
|
| - if (observers_.empty())
|
| + if (pending_begin_frame_observers_.empty())
|
| time_source_->SetActive(false);
|
| }
|
|
|
| void BackToBackBeginFrameSource::DidFinishFrame(BeginFrameObserver* obs,
|
| - size_t remaining_frames) {
|
| - if (remaining_frames == 0 && observers_.find(obs) != observers_.end()) {
|
| + const BeginFrameAck& ack) {
|
| + if (ack.remaining_frames == 0 && observers_.find(obs) != observers_.end()) {
|
| pending_begin_frame_observers_.insert(obs);
|
| time_source_->SetActive(true);
|
| }
|
| @@ -97,22 +133,23 @@ void BackToBackBeginFrameSource::OnTimerTick() {
|
| base::TimeTicks frame_time = time_source_->LastTickTime();
|
| base::TimeDelta default_interval = BeginFrameArgs::DefaultInterval();
|
| BeginFrameArgs args = BeginFrameArgs::Create(
|
| - BEGINFRAME_FROM_HERE, frame_time, frame_time + default_interval,
|
| - default_interval, BeginFrameArgs::NORMAL);
|
| + BEGINFRAME_FROM_HERE, source_id(), next_sequence_number_++, frame_time,
|
| + frame_time + default_interval, default_interval, BeginFrameArgs::NORMAL);
|
|
|
| // This must happen after getting the LastTickTime() from the time source.
|
| time_source_->SetActive(false);
|
|
|
| std::unordered_set<BeginFrameObserver*> pending_observers;
|
| pending_observers.swap(pending_begin_frame_observers_);
|
| - for (BeginFrameObserver* obs : pending_observers)
|
| + for (BeginFrameObserver* obs : pending_observers) {
|
| obs->OnBeginFrame(args);
|
| + }
|
| }
|
|
|
| // DelayBasedBeginFrameSource ---------------------------------------------
|
| DelayBasedBeginFrameSource::DelayBasedBeginFrameSource(
|
| std::unique_ptr<DelayBasedTimeSource> time_source)
|
| - : time_source_(std::move(time_source)) {
|
| + : time_source_(std::move(time_source)), current_sequence_number_(1) {
|
| time_source_->SetClient(this);
|
| }
|
|
|
| @@ -139,11 +176,12 @@ void DelayBasedBeginFrameSource::SetAuthoritativeVSyncInterval(
|
| }
|
|
|
| BeginFrameArgs DelayBasedBeginFrameSource::CreateBeginFrameArgs(
|
| + uint64_t sequence_number,
|
| base::TimeTicks frame_time,
|
| BeginFrameArgs::BeginFrameArgsType type) {
|
| - return BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time,
|
| - time_source_->NextTickTime(),
|
| - time_source_->Interval(), type);
|
| + return BeginFrameArgs::Create(
|
| + BEGINFRAME_FROM_HERE, source_id(), sequence_number, frame_time,
|
| + time_source_->NextTickTime(), time_source_->Interval(), type);
|
| }
|
|
|
| void DelayBasedBeginFrameSource::AddObserver(BeginFrameObserver* obs) {
|
| @@ -153,9 +191,16 @@ void DelayBasedBeginFrameSource::AddObserver(BeginFrameObserver* obs) {
|
| observers_.insert(obs);
|
| obs->OnBeginFrameSourcePausedChanged(false);
|
| time_source_->SetActive(true);
|
| + base::TimeTicks frame_time =
|
| + time_source_->NextTickTime() - time_source_->Interval();
|
| + if (current_begin_frame_time_ != frame_time) {
|
| + // Increment the sequence number if we are producing a frame that is
|
| + // different from the latest one we sent out.
|
| + current_sequence_number_++;
|
| + current_begin_frame_time_ = frame_time;
|
| + }
|
| BeginFrameArgs args = CreateBeginFrameArgs(
|
| - time_source_->NextTickTime() - time_source_->Interval(),
|
| - BeginFrameArgs::MISSED);
|
| + current_sequence_number_, frame_time, BeginFrameArgs::MISSED);
|
| BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs();
|
| if (!last_args.IsValid() ||
|
| (args.frame_time >
|
| @@ -178,8 +223,10 @@ bool DelayBasedBeginFrameSource::IsThrottled() const {
|
| }
|
|
|
| void DelayBasedBeginFrameSource::OnTimerTick() {
|
| - BeginFrameArgs args = CreateBeginFrameArgs(time_source_->LastTickTime(),
|
| + BeginFrameArgs args = CreateBeginFrameArgs(++current_sequence_number_,
|
| + time_source_->LastTickTime(),
|
| BeginFrameArgs::NORMAL);
|
| + current_begin_frame_time_ = args.frame_time;
|
| std::unordered_set<BeginFrameObserver*> observers(observers_);
|
| for (auto* obs : observers) {
|
| BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs();
|
| @@ -190,6 +237,100 @@ void DelayBasedBeginFrameSource::OnTimerTick() {
|
| }
|
| }
|
|
|
| +// BeginFrameObserverAckTracker -------------------------------------------
|
| +BeginFrameObserverAckTracker::BeginFrameObserverAckTracker()
|
| + : current_source_id_(0),
|
| + current_sequence_number_(1),
|
| + observers_had_updates_(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_updates_ = 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 not to use the BeginFrame.
|
| + if (obs->LastUsedBeginFrameArgs().sequence_number != current_sequence_number_)
|
| + finished_observers_.insert(obs);
|
| +}
|
| +
|
| +void BeginFrameObserverAckTracker::SourceChanged(const BeginFrameArgs& args) {
|
| + current_source_id_ = args.source_id;
|
| + current_sequence_number_ = args.sequence_number;
|
| +
|
| + // We have no choice but to consider everyone up to date up to the last frame.
|
| + for (auto& entry : oldest_incorporated_frames_) {
|
| + entry.second = current_sequence_number_ - 1;
|
| + }
|
| +}
|
| +
|
| +void BeginFrameObserverAckTracker::OnObserverFinishedFrame(
|
| + BeginFrameObserver* obs,
|
| + const BeginFrameAck& ack) {
|
| + if (ack.source_id != current_source_id_)
|
| + return;
|
| +
|
| + DCHECK_LE(ack.sequence_number, current_sequence_number_);
|
| + // Only consider acks for the current frame.
|
| + if (ack.sequence_number != current_sequence_number_)
|
| + return;
|
| +
|
| + finished_observers_.insert(obs);
|
| + observers_had_updates_ |= ack.has_updates;
|
| +
|
| + // We max() with the current value in |oldest_incorporated_frames_| to handle
|
| + // situations where an observer just started observing (again) and may
|
| + // acknowledge with an ancient oldest_incorporated_frame.
|
| + oldest_incorporated_frames_[obs] =
|
| + std::max(ack.oldest_incorporated_frame, oldest_incorporated_frames_[obs]);
|
| +}
|
| +
|
| +void BeginFrameObserverAckTracker::OnObserverAdded(BeginFrameObserver* obs) {
|
| + observers_.insert(obs);
|
| +
|
| + // Since the observer didn't want BeginFrames before, we consider it "fresh"
|
| + // up to the last BeginFrame.
|
| + oldest_incorporated_frames_[obs] = current_sequence_number_ - 1;
|
| +}
|
| +
|
| +void BeginFrameObserverAckTracker::OnObserverRemoved(BeginFrameObserver* obs) {
|
| + observers_.erase(obs);
|
| + finished_observers_.erase(obs);
|
| + oldest_incorporated_frames_.erase(obs);
|
| +}
|
| +
|
| +bool BeginFrameObserverAckTracker::AllObserversFinishedFrame() const {
|
| + return base::STLIncludes(finished_observers_, observers_);
|
| +}
|
| +
|
| +bool BeginFrameObserverAckTracker::AnyObserversHadUpdates() const {
|
| + return observers_had_updates_;
|
| +}
|
| +
|
| +uint64_t BeginFrameObserverAckTracker::OldestIncorporatedFrame() const {
|
| + uint64_t oldest_incorporated_frame = current_sequence_number_;
|
| + for (const auto& entry : oldest_incorporated_frames_) {
|
| + oldest_incorporated_frame =
|
| + std::min(oldest_incorporated_frame, entry.second);
|
| + }
|
| + return oldest_incorporated_frame;
|
| +}
|
| +
|
| +// ExternalBeginFrameSource -----------------------------------------------
|
| ExternalBeginFrameSource::ExternalBeginFrameSource(
|
| ExternalBeginFrameSourceClient* client)
|
| : client_(client) {
|
| @@ -204,6 +345,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);
|
| @@ -212,8 +354,11 @@ void ExternalBeginFrameSource::AddObserver(BeginFrameObserver* obs) {
|
| if (missed_begin_frame_args_.IsValid()) {
|
| BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs();
|
| if (!last_args.IsValid() ||
|
| - (missed_begin_frame_args_.frame_time > last_args.frame_time)) {
|
| + (missed_begin_frame_args_.source_id != last_args.source_id) ||
|
| + (missed_begin_frame_args_.sequence_number >
|
| + last_args.sequence_number)) {
|
| obs->OnBeginFrame(missed_begin_frame_args_);
|
| + ack_tracker_.OnObserverBeginFrame(obs, missed_begin_frame_args_);
|
| }
|
| }
|
| }
|
| @@ -223,12 +368,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;
|
| }
|
| @@ -243,11 +396,63 @@ 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_.OldestIncorporatedFrame(), 0,
|
| + ack_tracker_.AnyObserversHadUpdates());
|
| + client_->OnDidFinishFrame(ack);
|
| +}
|
| +
|
| +// DelegatingBeginFrameSource ---------------------------------------------
|
| +DelegatingBeginFrameSource::DelegatingBeginFrameSource(
|
| + BeginFrameSource* delegate)
|
| + : delegate_(delegate) {
|
| + DCHECK(delegate_);
|
| +}
|
| +
|
| +void DelegatingBeginFrameSource::DidFinishFrame(BeginFrameObserver* obs,
|
| + const BeginFrameAck& ack) {
|
| + delegate_->DidFinishFrame(obs, ack);
|
| +}
|
| +
|
| +void DelegatingBeginFrameSource::AddObserver(BeginFrameObserver* obs) {
|
| + delegate_->AddObserver(obs);
|
| +}
|
| +
|
| +void DelegatingBeginFrameSource::RemoveObserver(BeginFrameObserver* obs) {
|
| + delegate_->RemoveObserver(obs);
|
| +}
|
| +
|
| +bool DelegatingBeginFrameSource::IsThrottled() const {
|
| + return delegate_->IsThrottled();
|
| +}
|
| +
|
| +uint64_t DelegatingBeginFrameSource::source_id() const {
|
| + return delegate_->source_id();
|
| }
|
|
|
| } // namespace cc
|
|
|