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

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: Scheduler tests now pass and the code is cleaner. Created 6 years, 7 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
« no previous file with comments | « cc/scheduler/frame_source.h ('k') | cc/scheduler/frame_source_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..3b436e724cb08bb9210d5ddc1991778ff264c1d2
--- /dev/null
+++ b/cc/scheduler/frame_source.cc
@@ -0,0 +1,351 @@
+// 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/debug/trace_event.h"
+#include "base/logging.h"
+#include "cc/scheduler/delay_based_time_source.h"
+#include "cc/scheduler/scheduler.h"
+#include "ui/gfx/frame_time.h"
+
+#define FRAMESOURCE_TYPESTRING(x) \
+ std::string x::TypeString() const { return #x; }
+
+namespace cc {
+
+BaseBeginFrameSource::BaseBeginFrameSource(BeginFrameSink* sink)
+ : frame_sink_(sink),
+ generate_frames_(false),
+ timebase_(),
+ interval_(BeginFrameArgs::DefaultInterval()) {
+}
+
+// BeginFrameSource ------------------------------------------------------
+void BaseBeginFrameSource::SetBeginFrameSink(BeginFrameSink* sink) {
+ DCHECK(sink);
+ frame_sink_ = sink;
+}
+BeginFrameSink* BaseBeginFrameSource::GetBeginFrameSink() const {
+ DCHECK(frame_sink_);
+ return frame_sink_;
+}
+
+void BaseBeginFrameSource::SetGenerateFrames(bool generate_frames) {
+ if (generate_frames_ != generate_frames) {
+ OnGenerateChange(generate_frames);
+ generate_frames_ = generate_frames;
+ }
+}
+
+bool BaseBeginFrameSource::IsGeneratingFrames() const {
+ return generate_frames_;
+}
+
+void BaseBeginFrameSource::PendingFrames(size_t count) {
+ OnPendingFrames(count);
+}
+
+void BaseBeginFrameSource::SetTimeBaseAndInterval(
+ const base::TimeTicks timebase,
+ const base::TimeDelta interval) {
+ base::TimeDelta newinterval = interval;
+ if (newinterval == base::TimeDelta())
+ newinterval = BeginFrameArgs::DefaultInterval();
+
+ OnTimeBaseAndIntervalChange(timebase, newinterval);
+
+ timebase_ = timebase;
+ interval_ = newinterval;
+}
+
+base::TimeTicks BaseBeginFrameSource::TimeBase() const {
+ return timebase_;
+}
+
+base::TimeDelta BaseBeginFrameSource::Interval() const {
+ return interval_;
+}
+
+scoped_ptr<base::Value> BaseBeginFrameSource::BeginFrameSourceAsValue() const {
+ scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue);
+ state->SetString("type", TypeString());
+ state->SetInteger("frame_source", reinterpret_cast<size_t>(this));
+ state->SetBoolean("generate_frames", generate_frames_);
+ state->SetDouble("timebase_us", timebase_.ToInternalValue());
+ state->SetDouble("interval_us", interval_.InMicroseconds());
+
+ ExtraAsValue(state.get());
+
+ return state.PassAs<base::Value>();
+}
+
+/*************************************************************************
+ *
+ */
+ProxyBeginFrameSource::ProxyBeginFrameSource(BeginFrameSink* sink,
+ BeginFrameSource* source)
+ : BaseBeginFrameSource(sink), source_(source) {
+ DCHECK(source_);
+ source_->SetBeginFrameSink(this);
+}
+
+// BeginFrameSink --------------------------------------------------------
+void ProxyBeginFrameSource::BeginFrame(const BeginFrameArgs& args) {
+ frame_sink_->BeginFrame(args);
+}
+
+// BaseBeginFrameSource ---------------------------------------------------
+
+FRAMESOURCE_TYPESTRING(ProxyBeginFrameSource);
+
+void ProxyBeginFrameSource::ExtraAsValue(base::DictionaryValue* state) const {
+ state->Set("source", source_->BeginFrameSourceAsValue().release());
+}
+
+void ProxyBeginFrameSource::OnGenerateChange(bool generate_frames) {
+ DCHECK(source_);
+ source_->SetGenerateFrames(generate_frames);
+}
+
+void ProxyBeginFrameSource::OnPendingFrames(size_t count) {
+ DCHECK(source_);
+ source_->PendingFrames(count);
+}
+
+void ProxyBeginFrameSource::OnTimeBaseAndIntervalChange(
+ const base::TimeTicks timebase,
+ const base::TimeDelta interval) {
+ DCHECK(source_);
+ source_->SetTimeBaseAndInterval(timebase, interval);
+}
+
+/*************************************************************************
+ *
+ */
+ThrottledBeginFrameSource::ThrottledBeginFrameSource(BeginFrameSink* sink,
+ BeginFrameSource* source,
+ base::TimeDelta interval)
+ : ProxyBeginFrameSource(sink, source), last_frame_args_() {
+ interval_ = interval;
+}
+
+// BeginFrameSink --------------------------------------------------------
+void ThrottledBeginFrameSource::BeginFrame(const BeginFrameArgs& args) {
+ if (last_frame_args_.IsValid() &&
+ last_frame_args_.frame_time + interval_ > args.frame_time)
+ return;
+ last_frame_args_ = args;
+ frame_sink_->BeginFrame(args);
+}
+
+// BeginFrameSource ------------------------------------------------------
+
+FRAMESOURCE_TYPESTRING(ThrottledBeginFrameSource)
+
+void ThrottledBeginFrameSource::ExtraAsValue(
+ base::DictionaryValue* state) const {
+ state->Set("source", source_->BeginFrameSourceAsValue().release());
+ state->Set("last_frame_args", last_frame_args_.AsValue().release());
+}
+
+/*************************************************************************/
+BackToBackBeginFrameSource::BackToBackBeginFrameSource(
+ BeginFrameSink* sink,
+ base::SingleThreadTaskRunner* task_runner)
+ : BaseBeginFrameSource(sink),
+ task_runner_(task_runner),
+ send_begin_frame_posted_(false) {
+ DCHECK(task_runner);
+}
+
+void BackToBackBeginFrameSource::ScheduleSendBeginFrameArgs() {
+ if (!generate_frames_)
+ return;
+
+ if (send_begin_frame_posted_)
+ return;
+
+ send_begin_frame_posted_ = true;
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&BackToBackBeginFrameSource::SendBeginFrameArgs,
+ base::Unretained(this)));
+}
+
+void BackToBackBeginFrameSource::SendBeginFrameArgs() {
+ 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_) {
+ // return;
+ // }
+
+ base::TimeTicks now = gfx::FrameTime::Now();
+ // TODO(mithro): Is a deadline of now+interval_ sane?
+ BeginFrameArgs args = BeginFrameArgs::Create(now, now + interval_, interval_);
+ frame_sink_->BeginFrame(args);
+}
+
+// BeginFrameSource ------------------------------------------------------
+
+FRAMESOURCE_TYPESTRING(BackToBackBeginFrameSource);
+
+void BackToBackBeginFrameSource::ExtraAsValue(
+ base::DictionaryValue* state) const {
+ state->SetBoolean("send_begin_frame_posted_", send_begin_frame_posted_);
+}
+
+void BackToBackBeginFrameSource::OnGenerateChange(bool generate_frames) {
+ ScheduleSendBeginFrameArgs();
+}
+
+void BackToBackBeginFrameSource::OnPendingFrames(size_t count) {
+ if (count == 0) {
+ ScheduleSendBeginFrameArgs();
+ }
+}
+
+/*************************************************************************/
+SyntheticBeginFrameSource::SyntheticBeginFrameSource(
+ BeginFrameSink* sink,
+ base::SingleThreadTaskRunner* task_runner,
+ base::TimeDelta interval)
+ : BaseBeginFrameSource(sink), task_runner_(task_runner) {
+ DCHECK(task_runner);
+ interval_ = interval;
+ if (gfx::FrameTime::TimestampsAreHighRes()) {
+ time_source_ = DelayBasedTimeSourceHighRes::Create(interval_, task_runner);
+ } else {
+ time_source_ = DelayBasedTimeSource::Create(interval_, task_runner);
+ }
+ time_source_->SetActive(false);
+ time_source_->SetClient(this);
+}
+
+SyntheticBeginFrameSource::~SyntheticBeginFrameSource() {
+ time_source_->SetActive(false);
+}
+
+BeginFrameArgs SyntheticBeginFrameSource::CreateBeginFrameArgs(
+ base::TimeTicks frame_time) {
+ base::TimeTicks deadline = time_source_->NextTickTime();
+ return BeginFrameArgs::Create(frame_time, deadline, interval_);
+}
+
+// TimeSourceClient ------------------------------------------------------
+
+void SyntheticBeginFrameSource::OnTimerTick() {
+ frame_sink_->BeginFrame(CreateBeginFrameArgs(time_source_->LastTickTime()));
+}
+
+// BeginFrameSource ------------------------------------------------------
+
+FRAMESOURCE_TYPESTRING(SyntheticBeginFrameSource);
+
+void SyntheticBeginFrameSource::ExtraAsValue(
+ base::DictionaryValue* state) const {
+ state->Set("time_source", time_source_->AsValue().release());
+}
+
+void SyntheticBeginFrameSource::OnGenerateChange(bool generate_frames) {
+ base::TimeTicks missed_tick_time = time_source_->SetActive(generate_frames);
+ if (!missed_tick_time.is_null()) {
+ frame_sink_->BeginFrame(CreateBeginFrameArgs(missed_tick_time));
+ }
+}
+
+void SyntheticBeginFrameSource::OnTimeBaseAndIntervalChange(
+ const base::TimeTicks timebase,
+ const base::TimeDelta interval) {
+ time_source_->SetTimebaseAndInterval(timebase, interval);
+}
+
+/*************************************************************************
+ * A virtual frame source which lets you switch between two other frame sources
+ * (making sure the BeginFrameArgs stays monotonic).
+ */
+DualBeginFrameSource::DualBeginFrameSource(
+ BeginFrameSink* sink,
+ scoped_ptr<BeginFrameSource> source_primary,
+ scoped_ptr<BeginFrameSource> source_secondary)
+ : BaseBeginFrameSource(sink),
+ last_frame_args_(),
+ source_foreground_(source_primary.Pass()),
+ source_background_(source_secondary.Pass()) {
+ source_foreground_->SetBeginFrameSink(this);
+ source_background_->SetBeginFrameSink(this);
+ SwitchSource(SourceForeground());
+}
+
+DualBeginFrameSource::~DualBeginFrameSource() {
+}
+
+void DualBeginFrameSource::SwitchSource(const BeginFrameSource* new_source) {
+ DCHECK(new_source == SourceForeground() || new_source == SourceBackground());
+
+ if (generate_frames_)
+ active_source_->SetGenerateFrames(false);
+
+ active_source_ = const_cast<BeginFrameSource*>(new_source);
+
+ if (generate_frames_)
+ active_source_->SetGenerateFrames(true);
+}
+
+const BeginFrameSource* DualBeginFrameSource::SourceForeground() const {
+ return source_foreground_.get();
+}
+
+const BeginFrameSource* DualBeginFrameSource::SourceBackground() const {
+ return source_background_.get();
+}
+
+// BeginFrameSink ------------------------------------------------------
+
+void DualBeginFrameSource::BeginFrame(const BeginFrameArgs& args) {
+ // When switching clock sources you can get a BeginFrameArgs with a
+ // frame_time before the last value.
+ BeginFrameArgs new_args = args;
+ if (last_frame_args_.frame_time > new_args.frame_time)
+ return;
+
+ last_frame_args_ = new_args;
+ frame_sink_->BeginFrame(new_args);
+}
+
+// BeginFrameSource ----------------------------------------------------
+
+FRAMESOURCE_TYPESTRING(DualBeginFrameSource)
+
+void DualBeginFrameSource::ExtraAsValue(base::DictionaryValue* state) const {
+ state->Set("last_frame_args", last_frame_args_.AsValue().release());
+ if (active_source_ == SourceForeground())
+ state->SetString("active", "primary");
+ if (active_source_ == SourceBackground())
+ state->SetString("active", "secondary");
+ state->Set("primary",
+ source_foreground_->BeginFrameSourceAsValue().release());
+ state->Set("secondary",
+ source_background_->BeginFrameSourceAsValue().release());
+}
+
+void DualBeginFrameSource::OnPendingFrames(size_t count) {
+ active_source_->PendingFrames(count);
+}
+
+void DualBeginFrameSource::OnGenerateChange(bool generate_frames) {
+ DCHECK(active_source_);
+ active_source_->SetGenerateFrames(generate_frames);
+}
+
+void DualBeginFrameSource::OnTimeBaseAndIntervalChange(
+ const base::TimeTicks timebase,
+ const base::TimeDelta interval) {
+ DCHECK_EQ(active_source_, source_foreground_); // TODO(mithro): Is this okay?
+ source_foreground_->SetTimeBaseAndInterval(timebase, interval);
+}
+
+} // namespace cc
« no previous file with comments | « cc/scheduler/frame_source.h ('k') | cc/scheduler/frame_source_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698