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

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 now uses frame sources, working on scheduler_unittests. 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
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..5bc18c5abed18308b05948a05eff90237c4364df
--- /dev/null
+++ b/cc/scheduler/frame_source.cc
@@ -0,0 +1,297 @@
+// 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_GETTYPE(x) \
+ std::string x::FrameSourceType() const { return #x; }
+
+namespace cc {
+
+BaseFrameSource::BaseFrameSource(FrameSink* sink) : frame_sink_(sink) {
+}
+
+void BaseFrameSource::SetSink(FrameSink* sink) {
+ frame_sink_ = sink;
+}
+
+void BaseFrameSource::SendBeginFrame(const BeginFrameArgs& args) {
+ DCHECK(frame_sink_);
+ frame_sink_->BeginFrame(args);
+}
+
+void BaseFrameSource::SetTimeBaseAndInterval(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ if (interval != base::TimeDelta())
+ interval_ = interval;
+}
+
+scoped_ptr<base::Value> BaseFrameSource::FrameSourceAsValue() const {
+ return BaseFrameSourceAsValue().PassAs<base::Value>();
+}
+
+scoped_ptr<base::DictionaryValue> BaseFrameSource::BaseFrameSourceAsValue()
+ const {
+ scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue);
+ state->SetString("type", FrameSourceType());
+ state->SetInteger("frame_source", reinterpret_cast<size_t>(this));
+ state->SetInteger("interval_us", interval_.InMicroseconds());
+ return state.PassAs<base::DictionaryValue>();
+}
+
+/**
+ *
+ */
+FRAMESOURCE_GETTYPE(ProxyFrameSource);
+
+ProxyFrameSource::ProxyFrameSource(FrameSink* sink, FrameSource* source)
+ : BaseFrameSource(sink), source_(source) {
+ DCHECK(source_);
+ source->SetSink(this);
+}
+
+void ProxyFrameSource::BeginFrame(const BeginFrameArgs& args) {
+ TRACE_EVENT0("frame_time", "ProxyFrameSource::BeginFrame");
+ SendBeginFrame(args);
+}
+
+void ProxyFrameSource::SetNeedsBeginFrame(bool needs_begin_frame) {
+ DCHECK(source_);
+ source_->SetNeedsBeginFrame(needs_begin_frame);
+}
+
+scoped_ptr<base::Value> ProxyFrameSource::FrameSourceAsValue() const {
+ scoped_ptr<base::DictionaryValue> state =
+ BaseFrameSource::BaseFrameSourceAsValue();
+ state->Set("source", source_->FrameSourceAsValue().release());
+ return state.PassAs<base::Value>();
+}
+
+void ProxyFrameSource::SetTimeBaseAndInterval(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ source_->SetTimeBaseAndInterval(timebase, interval);
+}
+
+/**
+ *
+ */
+FRAMESOURCE_GETTYPE(ThrottledFrameSource)
+
+ThrottledFrameSource::ThrottledFrameSource(FrameSink* sink,
+ scoped_ptr<FrameSource> source,
+ base::TimeDelta interval)
+ : BaseFrameSource(sink), last_frame_args_(), source_(source.Pass()) {
+ interval_ = interval;
+ DCHECK(source_);
+ source_->SetSink(this);
+}
+
+ThrottledFrameSource::~ThrottledFrameSource() {
+}
+
+void ThrottledFrameSource::BeginFrame(const BeginFrameArgs& args) {
+ if (last_frame_args_.IsValid() &&
+ last_frame_args_.frame_time + interval_ > args.frame_time)
+ return;
+ last_frame_args_ = args;
+ SendBeginFrame(args);
+}
+
+void ThrottledFrameSource::SetNeedsBeginFrame(bool needs_begin_frame) {
+ source_->SetNeedsBeginFrame(needs_begin_frame);
+}
+
+void ThrottledFrameSource::SetTimeBaseAndInterval(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ source_->SetTimeBaseAndInterval(timebase, interval);
+}
+
+scoped_ptr<base::Value> ThrottledFrameSource::FrameSourceAsValue() const {
+ scoped_ptr<base::DictionaryValue> state =
+ BaseFrameSource::BaseFrameSourceAsValue();
+ state->Set("source", source_->FrameSourceAsValue().release());
+ state->Set("last_frame_args", last_frame_args_.AsValue().release());
+ return state.PassAs<base::Value>();
+}
+
+/**
+ *
+ */
+TaskRunnerFrameSource::TaskRunnerFrameSource(
+ FrameSink* sink,
+ base::SingleThreadTaskRunner* task_runner)
+ : BaseFrameSource(sink), task_runner_(task_runner) {
+ DCHECK(task_runner);
+}
+
+/**
+ * A frame source which sends a BeginFrame as soon as SetNeedsBeginFrame is
+ * requested.
+ */
+FRAMESOURCE_GETTYPE(BackToBackFrameSource)
+
+BackToBackFrameSource::BackToBackFrameSource(
+ FrameSink* sink,
+ base::SingleThreadTaskRunner* task_runner)
+ : TaskRunnerFrameSource(sink, task_runner) {
+}
+
+void BackToBackFrameSource::SetNeedsBeginFrame(bool needs_begin_frame) {
+ if (needs_begin_frame) {
brianderson 2014/05/07 17:20:16 Which solution are you leaning towards for solving
mithro-old 2014/05/07 22:02:32 Yeah, I'm leaning towards the ReadyForNextBeginFra
brianderson 2014/05/08 21:08:15 I've changed my mind here. Let's just keep the sin
mithro-old 2014/05/09 02:45:58 Are you saying that SetNeedsBeginFrame should be e
+ /* task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&BackToBackFrameSource::PostBeginFrame,
+ this)); */
+ }
+}
+
+void BackToBackFrameSource::PostBeginFrame() {
+ base::TimeTicks now = gfx::FrameTime::Now();
+ BeginFrameArgs args =
+ BeginFrameArgs::Create(now, base::TimeTicks(), base::TimeDelta());
+ SendBeginFrame(args);
+}
+
+/**
+ *
+ */
+
+SyntheticFrameSource::~SyntheticFrameSource() {
+}
+
+FRAMESOURCE_GETTYPE(SyntheticFrameSource);
+SyntheticFrameSource::SyntheticFrameSource(
+ FrameSink* sink,
+ base::SingleThreadTaskRunner* task_runner,
+ base::TimeDelta interval)
+ : TaskRunnerFrameSource(sink, 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_->SetClient(this);
+}
+
+// Activates future BeginFrames and, if activating, pushes the most
+// recently missed BeginFrame to the back of a retroactive queue.
+void SyntheticFrameSource::SetNeedsBeginFrame(bool needs_begin_frame) {
+ base::TimeTicks missed_tick_time = time_source_->SetActive(needs_begin_frame);
+ if (!missed_tick_time.is_null()) {
+ BeginFrameArgs args(CreateSyntheticBeginFrameArgs(missed_tick_time));
+ SendBeginFrame(args);
+ }
+}
+
+// Updates the phase and frequency of the timer.
+void SyntheticFrameSource::SetTimeBaseAndInterval(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ TaskRunnerFrameSource::SetTimeBaseAndInterval(timebase, interval);
+ time_source_->SetTimebaseAndInterval(timebase, interval);
+}
+
+scoped_ptr<base::Value> SyntheticFrameSource::FrameSourceAsValue() const {
+ scoped_ptr<base::DictionaryValue> state =
+ BaseFrameSource::BaseFrameSourceAsValue();
+ // state->Set("source", source_->FrameSourceAsValue().Pass());
+ return state.PassAs<base::Value>();
+}
+
+// TimeSourceClient implementation of OnTimerTick triggers a BeginFrame.
+void SyntheticFrameSource::OnTimerTick() {
+ BeginFrameArgs args(
+ CreateSyntheticBeginFrameArgs(time_source_->LastTickTime()));
+ SendBeginFrame(args);
+}
+
+BeginFrameArgs SyntheticFrameSource::CreateSyntheticBeginFrameArgs(
+ base::TimeTicks frame_time) {
+ base::TimeTicks deadline =
+ time_source_->NextTickTime(); // scheduler_->EstimatedParentDrawTime();
+ return BeginFrameArgs::Create(
+ frame_time, deadline, interval_); // scheduler_->VSyncInterval());
+}
+
+/**
+ * A virtual frame source which lets you switch between two other frame sources
+ * (making sure the BeginFrameArgs stays monotonic).
+ */
+FRAMESOURCE_GETTYPE(DualFrameSource)
+
+DualFrameSource::DualFrameSource(FrameSink* sink,
+ scoped_ptr<FrameSource> source_primary,
+ scoped_ptr<FrameSource> source_secondary)
+ : BaseFrameSource(sink),
+ needs_begin_frame_(false),
+ last_frame_args_(),
+ source_primary_(source_primary.Pass()),
+ source_secondary_(source_secondary.Pass()) {
+ source_primary_->SetSink(this);
+ source_secondary_->SetSink(this);
+ SwitchSource(SourcePrimary());
+}
+
+DualFrameSource::~DualFrameSource() {
+}
+
+void DualFrameSource::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;
+ BaseFrameSource::SendBeginFrame(new_args);
+}
+
+void DualFrameSource::SetNeedsBeginFrame(bool needs_begin_frame) {
+ DCHECK(active_source_);
+ needs_begin_frame_ = needs_begin_frame;
+ active_source_->SetNeedsBeginFrame(needs_begin_frame);
+}
+
+scoped_ptr<base::Value> DualFrameSource::FrameSourceAsValue() const {
+ scoped_ptr<base::DictionaryValue> state =
+ BaseFrameSource::BaseFrameSourceAsValue();
+ if (active_source_ == SourcePrimary())
+ state->SetString("active", "primary");
+ if (active_source_ == SourceSecondary())
+ state->SetString("active", "secondary");
+ state->Set("primary", source_primary_->FrameSourceAsValue().release());
+ state->Set("secondary", source_secondary_->FrameSourceAsValue().release());
+ state->Set("last_frame_args", last_frame_args_.AsValue().release());
+ return state.PassAs<base::Value>();
+}
+
+// ---------------------------------------------------------------------
+
+void DualFrameSource::SwitchSource(const FrameSource* new_source) {
+ DCHECK(new_source == SourcePrimary() || new_source == SourceSecondary());
brianderson 2014/05/07 17:20:16 Can we avoid exposing the underlying frame sources
mithro-old 2014/05/07 22:02:32 I originally started with an enum. After adding t
brianderson 2014/05/08 00:55:58 Do we need to expose the underlying sources at all
mithro-old 2014/05/09 02:45:58 As the DualFrameSource takes ownership of the sour
+
+ if (needs_begin_frame_)
+ active_source_->SetNeedsBeginFrame(false);
+
+ active_source_ = const_cast<FrameSource*>(new_source);
+
+ if (needs_begin_frame_)
+ active_source_->SetNeedsBeginFrame(true);
+}
+
+const FrameSource* DualFrameSource::SourcePrimary() const {
+ return source_primary_.get();
+}
+
+const FrameSource* DualFrameSource::SourceSecondary() const {
+ return source_secondary_.get();
+}
+
+} // namespace cc

Powered by Google App Engine
This is Rietveld 408576698