| Index: cc/scheduler/begin_frame_source.cc | 
| diff --git a/cc/scheduler/begin_frame_source.cc b/cc/scheduler/begin_frame_source.cc | 
| index 4c859a7b53c89c81a0aa8ee738ecc0d806607600..a7ba684d934c6ca5564ce6181d00fd18768c959c 100644 | 
| --- a/cc/scheduler/begin_frame_source.cc | 
| +++ b/cc/scheduler/begin_frame_source.cc | 
| @@ -6,6 +6,7 @@ | 
|  | 
| #include <stddef.h> | 
|  | 
| +#include "base/atomic_sequence_num.h" | 
| #include "base/auto_reset.h" | 
| #include "base/location.h" | 
| #include "base/logging.h" | 
| @@ -25,7 +26,7 @@ namespace { | 
| static const double kDoubleTickDivisor = 2.0; | 
| } | 
|  | 
| -// BeginFrameObserverBase ----------------------------------------------- | 
| +// BeginFrameObserverBase ------------------------------------------------- | 
| BeginFrameObserverBase::BeginFrameObserverBase() | 
| : last_begin_frame_args_(), dropped_begin_frame_args_(0) { | 
| } | 
| @@ -33,9 +34,12 @@ BeginFrameObserverBase::BeginFrameObserverBase() | 
| const BeginFrameArgs& BeginFrameObserverBase::LastUsedBeginFrameArgs() const { | 
| return last_begin_frame_args_; | 
| } | 
| + | 
| void BeginFrameObserverBase::OnBeginFrame(const BeginFrameArgs& args) { | 
| DCHECK(args.IsValid()); | 
| DCHECK(args.frame_time >= last_begin_frame_args_.frame_time); | 
| +  DCHECK(args.sequence_number > last_begin_frame_args_.sequence_number || | 
| +         args.source_id != last_begin_frame_args_.source_id); | 
| bool used = OnBeginFrameDerivedImpl(args); | 
| if (used) { | 
| last_begin_frame_args_ = args; | 
| @@ -44,17 +48,31 @@ void BeginFrameObserverBase::OnBeginFrame(const BeginFrameArgs& args) { | 
| } | 
| } | 
|  | 
| +// BeginFrameSource ------------------------------------------------------- | 
| +namespace { | 
| +static base::StaticAtomicSequenceNumber g_next_source_id; | 
| +}  // namespace | 
| + | 
| +BeginFrameSource::BeginFrameSource() : source_id_(g_next_source_id.GetNext()) {} | 
| + | 
| +uint32_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_(BeginFrameArgs::kStartingFrameNumber), | 
| +      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. | 
| @@ -97,8 +115,9 @@ 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); | 
| +  next_sequence_number_++; | 
|  | 
| // This must happen after getting the LastTickTime() from the time source. | 
| time_source_->SetActive(false); | 
| @@ -113,7 +132,8 @@ void BackToBackBeginFrameSource::OnTimerTick() { | 
| // DelayBasedBeginFrameSource --------------------------------------------- | 
| DelayBasedBeginFrameSource::DelayBasedBeginFrameSource( | 
| std::unique_ptr<DelayBasedTimeSource> time_source) | 
| -    : time_source_(std::move(time_source)) { | 
| +    : time_source_(std::move(time_source)), | 
| +      next_sequence_number_(BeginFrameArgs::kStartingFrameNumber) { | 
| time_source_->SetClient(this); | 
| } | 
|  | 
| @@ -142,9 +162,10 @@ void DelayBasedBeginFrameSource::SetAuthoritativeVSyncInterval( | 
| BeginFrameArgs DelayBasedBeginFrameSource::CreateBeginFrameArgs( | 
| base::TimeTicks frame_time, | 
| BeginFrameArgs::BeginFrameArgsType type) { | 
| -  return BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, | 
| -                                time_source_->NextTickTime(), | 
| -                                time_source_->Interval(), type); | 
| +  uint64_t sequence_number = next_sequence_number_++; | 
| +  return BeginFrameArgs::Create( | 
| +      BEGINFRAME_FROM_HERE, source_id(), sequence_number, frame_time, | 
| +      time_source_->NextTickTime(), time_source_->Interval(), type); | 
| } | 
|  | 
| void DelayBasedBeginFrameSource::AddObserver(BeginFrameObserver* obs) { | 
| @@ -154,14 +175,33 @@ void DelayBasedBeginFrameSource::AddObserver(BeginFrameObserver* obs) { | 
| observers_.insert(obs); | 
| obs->OnBeginFrameSourcePausedChanged(false); | 
| time_source_->SetActive(true); | 
| -  BeginFrameArgs args = CreateBeginFrameArgs( | 
| -      time_source_->NextTickTime() - time_source_->Interval(), | 
| -      BeginFrameArgs::MISSED); | 
| + | 
| +  // Missed args should correspond to |current_begin_frame_args_| (particularly, | 
| +  // have the same sequence number) if |current_begin_frame_args_| still | 
| +  // correspond to the last time the time source should have ticked. This may | 
| +  // not be the case if OnTimerTick() has never run yet, the time source was | 
| +  // inactive before AddObserver() was called, or the interval changed. In such | 
| +  // a case, we create new args with a new sequence number. | 
| +  base::TimeTicks last_or_missed_tick_time = | 
| +      time_source_->NextTickTime() - time_source_->Interval(); | 
| +  if (current_begin_frame_args_.IsValid() && | 
| +      current_begin_frame_args_.frame_time == last_or_missed_tick_time && | 
| +      current_begin_frame_args_.interval == time_source_->Interval()) { | 
| +    // Ensure that the args have the right type. | 
| +    current_begin_frame_args_.type = BeginFrameArgs::MISSED; | 
| +  } else { | 
| +    // The args are not up to date and we need to create new ones with the | 
| +    // missed tick's time and a new sequence number. | 
| +    current_begin_frame_args_ = | 
| +        CreateBeginFrameArgs(last_or_missed_tick_time, BeginFrameArgs::MISSED); | 
| +  } | 
| + | 
| BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs(); | 
| if (!last_args.IsValid() || | 
| -      (args.frame_time > | 
| -       last_args.frame_time + args.interval / kDoubleTickDivisor)) { | 
| -    obs->OnBeginFrame(args); | 
| +      (current_begin_frame_args_.frame_time > | 
| +       last_args.frame_time + | 
| +           current_begin_frame_args_.interval / kDoubleTickDivisor)) { | 
| +    obs->OnBeginFrame(current_begin_frame_args_); | 
| } | 
| } | 
|  | 
| @@ -179,18 +219,21 @@ bool DelayBasedBeginFrameSource::IsThrottled() const { | 
| } | 
|  | 
| void DelayBasedBeginFrameSource::OnTimerTick() { | 
| -  BeginFrameArgs args = CreateBeginFrameArgs(time_source_->LastTickTime(), | 
| -                                             BeginFrameArgs::NORMAL); | 
| +  current_begin_frame_args_ = CreateBeginFrameArgs(time_source_->LastTickTime(), | 
| +                                                   BeginFrameArgs::NORMAL); | 
| std::unordered_set<BeginFrameObserver*> observers(observers_); | 
| for (auto* obs : observers) { | 
| BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs(); | 
| if (!last_args.IsValid() || | 
| -        (args.frame_time > | 
| -         last_args.frame_time + args.interval / kDoubleTickDivisor)) | 
| -      obs->OnBeginFrame(args); | 
| +        (current_begin_frame_args_.frame_time > | 
| +         last_args.frame_time + | 
| +             current_begin_frame_args_.interval / kDoubleTickDivisor)) { | 
| +      obs->OnBeginFrame(current_begin_frame_args_); | 
| +    } | 
| } | 
| } | 
|  | 
| +// ExternalBeginFrameSource ----------------------------------------------- | 
| ExternalBeginFrameSource::ExternalBeginFrameSource( | 
| ExternalBeginFrameSourceClient* client) | 
| : client_(client) { | 
| @@ -214,6 +257,9 @@ void ExternalBeginFrameSource::AddObserver(BeginFrameObserver* obs) { | 
| BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs(); | 
| if (!last_args.IsValid() || | 
| (missed_begin_frame_args_.frame_time > last_args.frame_time)) { | 
| +      DCHECK((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_); | 
| } | 
| } | 
|  |