Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(735)

Unified Diff: cc/scheduler/begin_frame_source.cc

Issue 2527283003: cc: Introduce BeginFrame sequence numbers and acknowledgements.
Patch Set: Address Brian's comments. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « cc/scheduler/begin_frame_source.h ('k') | cc/scheduler/begin_frame_source_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..923d3efc57fa11cf90b76fde98896a95e0d0cddb 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_(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.
@@ -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,8 +133,8 @@ 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);
@@ -139,11 +175,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,14 +190,31 @@ 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);
+
+ // Check if |current_begin_frame_args_| are still valid. They may not be valid
+ // if OnTimerTick() has never run yet, the time source was inactive before
+ // AddObserver() was called, or the interval changed.
+ 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 invalid, we need to create new ones with the missed tick's
+ // time and a new sequence number.
+ current_begin_frame_args_ =
+ CreateBeginFrameArgs(current_begin_frame_args_.sequence_number + 1,
+ 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_);
}
}
@@ -178,18 +232,115 @@ bool DelayBasedBeginFrameSource::IsThrottled() const {
}
void DelayBasedBeginFrameSource::OnTimerTick() {
- BeginFrameArgs args = CreateBeginFrameArgs(time_source_->LastTickTime(),
- BeginFrameArgs::NORMAL);
+ current_begin_frame_args_ = CreateBeginFrameArgs(
+ current_begin_frame_args_.sequence_number + 1,
+ 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_);
}
}
+// 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 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 : latest_confirmed_frames_) {
+ DCHECK_LT(BeginFrameArgs::kInvalidFrameNumber, current_sequence_number_);
+ 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_damage_ |= ack.has_damage;
+
+ // We max() with the current value in |latest_confirmed_frames_| to handle
+ // situations where an observer just started observing (again) and may
+ // acknowledge with an ancient latest_confirmed_frame.
+ latest_confirmed_frames_[obs] =
+ std::max(ack.latest_confirmed_frame, latest_confirmed_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.
+ DCHECK_LT(BeginFrameArgs::kInvalidFrameNumber, current_sequence_number_);
+ latest_confirmed_frames_[obs] = current_sequence_number_ - 1;
+}
+
+void BeginFrameObserverAckTracker::OnObserverRemoved(BeginFrameObserver* obs) {
+ observers_.erase(obs);
+ finished_observers_.erase(obs);
+ latest_confirmed_frames_.erase(obs);
+}
+
+bool BeginFrameObserverAckTracker::AllObserversFinishedFrame() const {
+ return base::STLIncludes(finished_observers_, observers_);
+}
+
+bool BeginFrameObserverAckTracker::AnyObserversHadDamage() const {
+ return observers_had_damage_;
+}
+
+uint64_t BeginFrameObserverAckTracker::LatestConfirmedFrame() const {
+ uint64_t latest_confirmed_frame = current_sequence_number_;
+ for (const auto& entry : latest_confirmed_frames_) {
+ latest_confirmed_frame = std::min(latest_confirmed_frame, entry.second);
+ }
+ return latest_confirmed_frame;
+}
+
+// ExternalBeginFrameSource -----------------------------------------------
ExternalBeginFrameSource::ExternalBeginFrameSource(
ExternalBeginFrameSourceClient* client)
: client_(client) {
@@ -204,6 +355,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 +364,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 +378,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 +406,59 @@ 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_.LatestConfirmedFrame(), 0,
+ ack_tracker_.AnyObserversHadDamage());
+ 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();
}
} // namespace cc
« no previous file with comments | « cc/scheduler/begin_frame_source.h ('k') | cc/scheduler/begin_frame_source_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698