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

Unified Diff: cc/scheduler/frame_source.cc

Issue 267783004: Refactoring the way begin frame sources inside scheduler work. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase onto master. Created 6 years, 3 months 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
Index: cc/scheduler/frame_source.cc
diff --git a/cc/scheduler/frame_source.cc b/cc/scheduler/frame_source.cc
new file mode 100644
index 0000000000000000000000000000000000000000..c7d57c3589a6cbefaec8955cf5ebdced39fb6b85
--- /dev/null
+++ b/cc/scheduler/frame_source.cc
@@ -0,0 +1,398 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/scheduler/frame_source.h"
+
+#include "base/auto_reset.h"
+#include "base/debug/trace_event.h"
+#include "base/debug/trace_event_argument.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "cc/scheduler/delay_based_time_source.h"
+#include "cc/scheduler/scheduler.h"
+#include "ui/gfx/frame_time.h"
+
+namespace cc {
+
+VSyncParameterObserver::VSyncParameterObserver(
+ base::TimeTicks initial_vsync_timebase,
+ base::TimeDelta initial_vsync_interval)
+ : vsync_timebase_(initial_vsync_timebase),
+ vsync_interval_(initial_vsync_interval) {
+}
+VSyncParameterObserver::~VSyncParameterObserver() {
+}
+
+void VSyncParameterObserver::OnUpdateVSyncParameters(
+ base::TimeTicks new_vsync_timebase,
+ base::TimeDelta new_vsync_interval) {
+ if (vsync_timebase_ != new_vsync_timebase ||
+ vsync_interval_ != new_vsync_interval) {
+ OnTimeBaseAndIntervalChange(new_vsync_timebase, new_vsync_interval);
+ }
+ vsync_timebase_ = new_vsync_timebase;
+ vsync_interval_ = new_vsync_interval;
+}
+
+base::TimeTicks VSyncParameterObserver::VSyncTimebase() const {
+ return vsync_timebase_;
+}
+
+base::TimeDelta VSyncParameterObserver::VSyncInterval() const {
+ return vsync_interval_;
+}
+
+// Tracing
+void VSyncParameterObserver::AsValueInto(base::debug::TracedValue* dict) const {
+ dict->SetInteger("vsync_timebase_us", vsync_timebase_.ToInternalValue());
+ dict->SetInteger("vsync_interval_us", vsync_interval_.InMicroseconds());
+}
+
+/*************************************************************************/
+
+void BeginFrameSource::AddObserver(BeginFrameObserver* obs) {
+ DCHECK(!observer_);
+ observer_ = obs;
+}
+
+void BeginFrameSource::RemoveObserver(BeginFrameObserver* obs) {
+ DCHECK_EQ(observer_, obs);
+ observer_ = NULL;
+}
+
+void BeginFrameSource::SendBeginFrame(const BeginFrameArgs& args) {
brianderson 2014/09/18 00:27:25 "Send" implies that we're sending a message. Shoul
mithro-old 2014/09/18 13:33:37 It can't actually be named OnBeginFrame otherwise
brianderson 2014/09/18 21:54:18 CallOnBeginFrame sgtm.
mithro-old 2014/09/19 02:45:38 Acknowledged.
+ if (observer_) {
+ observer_->OnBeginFrame(args);
+ }
+}
+
+// Tracing support
+void BeginFrameSource::AsValueInto(base::debug::TracedValue* dict) const {
+ // As the observer might try to trace the source, prevent an infinte loop
+ // from occuring.
+ if (inside_as_value_into_) {
+ dict->SetString("observer", "<loop detected>");
+ return;
+ }
+
+ if (observer_) {
+ base::AutoReset<bool> prevent_loops(
+ const_cast<bool*>(&inside_as_value_into_), true);
+ dict->BeginDictionary("observer");
+ observer_->AsValueInto(dict);
+ dict->EndDictionary();
+ } else {
+ dict->SetString("observer", "NULL");
+ }
+}
+
+/*************************************************************************/
+scoped_ptr<BackToBackBeginFrameSource> BackToBackBeginFrameSource::Create(
+ base::SingleThreadTaskRunner* task_runner) {
+ return make_scoped_ptr(new BackToBackBeginFrameSource(task_runner));
+}
+
+BackToBackBeginFrameSource::BackToBackBeginFrameSource(
+ base::SingleThreadTaskRunner* task_runner)
+ : weak_factory_(this),
+ task_runner_(task_runner),
+ needs_begin_frames_(false),
+ send_begin_frame_posted_(false) {
+ DCHECK(task_runner);
+}
+
+BackToBackBeginFrameSource::~BackToBackBeginFrameSource() {
+}
+
+base::TimeTicks BackToBackBeginFrameSource::Now() {
+ return gfx::FrameTime::Now();
+}
+
+void BackToBackBeginFrameSource::ScheduleSendBeginFrameArgs() {
brianderson 2014/09/18 00:27:25 ScheduleBeginFrame?
mithro-old 2014/09/18 13:33:37 Done.
+ if (!needs_begin_frames_)
+ return;
+
+ if (send_begin_frame_posted_)
+ return;
+
+ send_begin_frame_posted_ = true;
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BackToBackBeginFrameSource::SendBeginFrameArgs,
+ weak_factory_.GetWeakPtr()));
+}
+
+void BackToBackBeginFrameSource::SendBeginFrameArgs() {
brianderson 2014/09/18 00:27:25 SendBeginFrame -> BeginFrame?
mithro-old 2014/09/18 13:33:37 Done.
+ send_begin_frame_posted_ = false;
+
+ // TODO(mithro): Fix the tests so this can be enabled. The tests currently
+ // depend on one begin frame firing after generate_frames_ is set false.
+ // if (!generate_frames_) {
brianderson 2014/09/18 00:27:25 Should this be !needs_begin_frames_? Why do the t
mithro-old 2014/09/18 13:33:37 Fixed.
+ // return;
+ // }
+
+ base::TimeTicks now = Now();
+ // Set deadline somewhere a long time in the future.
brianderson 2014/09/18 00:27:25 Comment doesn't match code anymore here.
mithro-old 2014/09/18 13:33:37 Removed.
+ BeginFrameArgs args =
+ BeginFrameArgs::Create(now,
+ now + BeginFrameArgs::DefaultInterval(),
+ BeginFrameArgs::DefaultInterval());
+ SendBeginFrame(args);
+}
+
+// BeginFrameSource ------------------------------------------------------
+bool BackToBackBeginFrameSource::NeedsBeginFrames() const {
+ return needs_begin_frames_;
+}
+
+void BackToBackBeginFrameSource::SetNeedsBeginFrames(bool needs_begin_frames) {
+ needs_begin_frames_ = needs_begin_frames;
+ ScheduleSendBeginFrameArgs();
+}
+
+void BackToBackBeginFrameSource::DidFinishFrame(size_t remaining_frames) {
+ if (remaining_frames == 0) {
+ ScheduleSendBeginFrameArgs();
+ }
+}
+
+// Tracing
+void BackToBackBeginFrameSource::AsValueInto(
+ base::debug::TracedValue* dict) const {
+ dict->SetString("type", "BackToBackBeginFrameSource");
+ BeginFrameSource::AsValueInto(dict);
+ dict->SetBoolean("send_begin_frame_posted_", send_begin_frame_posted_);
+ dict->SetBoolean("needs_begin_frames", needs_begin_frames_);
+}
+
+/*************************************************************************/
+
+scoped_ptr<SyntheticBeginFrameSource> SyntheticBeginFrameSource::Create(
+ base::SingleThreadTaskRunner* task_runner,
+ base::TimeTicks initial_vsync_timebase,
+ base::TimeDelta initial_vsync_interval) {
+ scoped_refptr<DelayBasedTimeSource> time_source;
+ if (gfx::FrameTime::TimestampsAreHighRes()) {
+ time_source = DelayBasedTimeSourceHighRes::Create(initial_vsync_interval,
+ task_runner);
+ } else {
+ time_source =
+ DelayBasedTimeSource::Create(initial_vsync_interval, task_runner);
+ }
+
+ return make_scoped_ptr(new SyntheticBeginFrameSource(
+ time_source, initial_vsync_timebase, initial_vsync_interval));
+}
+
+SyntheticBeginFrameSource::SyntheticBeginFrameSource(
+ scoped_refptr<DelayBasedTimeSource> time_source,
+ base::TimeTicks initial_vsync_timebase,
+ base::TimeDelta initial_vsync_interval)
+ : BeginFrameSource(),
+ VSyncParameterObserver(initial_vsync_timebase, initial_vsync_interval),
+ time_source_(time_source) {
+ time_source_->SetActive(false);
+ time_source_->SetClient(this);
+}
+
+SyntheticBeginFrameSource::~SyntheticBeginFrameSource() {
+ if (NeedsBeginFrames())
+ time_source_->SetActive(false);
+}
+
+void SyntheticBeginFrameSource::OnTimeBaseAndIntervalChange(
+ const base::TimeTicks new_vsync_timebase,
+ const base::TimeDelta new_vsync_interval) {
+ time_source_->SetTimebaseAndInterval(new_vsync_timebase, new_vsync_interval);
+}
+
+void SyntheticBeginFrameSource::SendBeginFrameFromTick(
brianderson 2014/09/18 00:27:25 Please roll this into OnTimerTick.
brianderson 2014/09/18 00:31:25 Nevermind about this one, I see how it's reused wh
mithro-old 2014/09/18 13:33:37 Acknowledged.
mithro-old 2014/09/18 13:33:37 Acknowledged.
+ base::TimeTicks frame_time) {
+ base::TimeTicks deadline = time_source_->NextTickTime();
+ SendBeginFrame(BeginFrameArgs::Create(frame_time, deadline, VSyncInterval()));
+}
+
+// TimeSourceClient
+void SyntheticBeginFrameSource::OnTimerTick() {
+ SendBeginFrameFromTick(time_source_->LastTickTime());
+}
+
+// BeginFrameSource
+void SyntheticBeginFrameSource::SetNeedsBeginFrames(bool needs_begin_frames) {
+ if (needs_begin_frames == NeedsBeginFrames())
+ return;
+
+ base::TimeTicks missed_tick_time =
+ time_source_->SetActive(needs_begin_frames);
+ if (!missed_tick_time.is_null()) {
+ SendBeginFrameFromTick(missed_tick_time);
+ }
+}
+
+bool SyntheticBeginFrameSource::NeedsBeginFrames() const {
+ return time_source_->Active();
+}
+
+// Tracing
+void SyntheticBeginFrameSource::AsValueInto(
+ base::debug::TracedValue* dict) const {
+ dict->SetString("type", "SyntheticBeginFrameSource");
+ BeginFrameSource::AsValueInto(dict);
+
+ dict->BeginDictionary("last_frame_args");
+ time_source_->AsValueInto(dict);
+ dict->EndDictionary();
+}
+
+/*************************************************************************/
+
+scoped_ptr<BeginFrameSourceMultiplexer> BeginFrameSourceMultiplexer::Create() {
+ return make_scoped_ptr(new BeginFrameSourceMultiplexer());
+}
+
+BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer()
+ : minimum_interval_(base::TimeDelta()),
+ active_source_(NULL),
+ source_list_() {
+}
+
+BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer(
+ base::TimeDelta minimum_interval)
+ : minimum_interval_(minimum_interval),
+ active_source_(NULL),
+ source_list_() {
+}
+
+BeginFrameSourceMultiplexer::~BeginFrameSourceMultiplexer() {
+}
+
+void BeginFrameSourceMultiplexer::SetActiveSource(
+ BeginFrameSource* new_source) {
+ DCHECK(HasSource(new_source) || new_source == NULL);
+
+ bool needs_begin_frames = NeedsBeginFrames();
+ if (active_source_) {
+ if (needs_begin_frames)
+ SetNeedsBeginFrames(false);
+
+ // Technically we shouldn't need to remove observation, but this prevents
+ // the case where SetNeedsBeginFrames message gets to the source after a
+ // message has already been sent.
+ active_source_->RemoveObserver(this);
+ active_source_ = NULL;
+ }
+ DCHECK(!active_source_);
+ active_source_ = new_source;
+
+ if (active_source_) {
+ active_source_->AddObserver(this);
+
+ if (needs_begin_frames) {
+ SetNeedsBeginFrames(true);
+ }
+ }
+}
+
+const BeginFrameSource* BeginFrameSourceMultiplexer::ActiveSource() {
+ return active_source_;
+}
+
+bool BeginFrameSourceMultiplexer::HasSource(BeginFrameSource* source) {
+ return (source_list_.find(source) != source_list_.end());
+}
+
+// ThrottledBeginFrameSource
+void BeginFrameSourceMultiplexer::AddSource(BeginFrameSource* new_source) {
+ DCHECK(new_source);
+ DCHECK(!HasSource(new_source));
+
+ source_list_.insert(new_source);
+
+ // If there is no active source, set the new one as the active one.
+ if (!active_source_)
+ SetActiveSource(new_source);
+}
+
+void BeginFrameSourceMultiplexer::RemoveSource(
+ BeginFrameSource* existing_source) {
+ DCHECK(existing_source);
+ DCHECK(HasSource(existing_source));
+ DCHECK_NE(existing_source, active_source_);
+ source_list_.erase(existing_source);
+}
+
+void BeginFrameSourceMultiplexer::SetMinimumInterval(
+ base::TimeDelta new_minimum_interval) {
+ DCHECK_GE(new_minimum_interval.ToInternalValue(), 0);
+ minimum_interval_ = new_minimum_interval;
+}
+
+// BeginFrameObserver
+void BeginFrameSourceMultiplexer::OnBeginFrame(const BeginFrameArgs& args) {
+ if (!observer_)
+ return;
+
+ if (observer_->LastBeginFrameArgs().IsValid() &&
+ observer_->LastBeginFrameArgs().frame_time + minimum_interval_ >
+ args.frame_time)
+ return;
+ SendBeginFrame(args);
+}
+
+const BeginFrameArgs& BeginFrameSourceMultiplexer::LastBeginFrameArgs() const {
+ return observer_->LastBeginFrameArgs();
+}
+
+// BeginFrameSource
+bool BeginFrameSourceMultiplexer::NeedsBeginFrames() const {
+ if (active_source_) {
+ return active_source_->NeedsBeginFrames();
+ } else {
+ return false;
+ }
+}
+
+void BeginFrameSourceMultiplexer::SetNeedsBeginFrames(bool needs_begin_frames) {
+ if (active_source_) {
+ active_source_->SetNeedsBeginFrames(needs_begin_frames);
+ } else {
+ DCHECK(!needs_begin_frames);
+ }
+}
+
+void BeginFrameSourceMultiplexer::DidFinishFrame(size_t remaining_frames) {
+ active_source_->DidFinishFrame(remaining_frames);
+}
+
+// Tracing
+void BeginFrameSourceMultiplexer::AsValueInto(
+ base::debug::TracedValue* dict) const {
+ dict->SetString("type", "BeginFrameSourceMultiplexer");
+
+ dict->SetInteger("minimum_interval_us", minimum_interval_.InMicroseconds());
+ if (observer_) {
+ dict->BeginDictionary("last_begin_frame_args");
+ observer_->LastBeginFrameArgs().AsValueInto(dict);
+ dict->EndDictionary();
+ }
+
+ if (active_source_) {
+ dict->BeginDictionary("active_source");
+ active_source_->AsValueInto(dict);
+ dict->EndDictionary();
+ } else {
+ dict->SetString("active_source", "NULL");
+ }
+
+ for (std::set<BeginFrameSource*>::const_iterator it = source_list_.begin();
+ it != source_list_.end();
+ ++it) {
+ dict->BeginDictionary(
+ base::SizeTToString(std::distance(source_list_.begin(), it)).c_str());
+ (*it)->AsValueInto(dict);
+ dict->EndDictionary();
+ }
+}
+
+} // namespace cc

Powered by Google App Engine
This is Rietveld 408576698