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

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: 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/output/begin_frame_args.h ('k') | cc/scheduler/scheduler.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..c4cf412508f7475939b5bbafc53153430f47982b
--- /dev/null
+++ b/cc/scheduler/frame_source.cc
@@ -0,0 +1,318 @@
+// Copyright 2011 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/scheduler.h"
+
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "cc/scheduler/delay_based_time_source.h"
+#include "ui/gfx/frame_time.h"
+
+namespace cc {
+
+class FrameSink {
+ public:
+ virtual void BeginFrame(BeginFrameArgs* args) = 0;
+};
+
+class FrameSource {
+ public:
+ FrameSource(FrameSink* sink) : sink_(sink) {}
+ virtual ~FrameSource() {}
+
+ virtual void SetSink(FrameSink* sink) { sink_ = sink; }
+
+ virtual void SendBeginFrame(BeginFrameArgs* args) {
+ DCHECK(sink_);
+ DCHECK(args);
+ sink_->BeginFrame(args);
+ }
+
+ virtual void SetNeedsBeginFrame(bool needs_begin_frame) = 0;
+
+ virtual void UpdateFrameSource(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ if (!interval.is_null())
+ interval_ = interval;
+ }
+
+ virtual scoped_ptr<base::Value> AsValue() const {
+ scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue);
+ state->SetString("type", GetType());
+ state->SetInteger("frame_source", this);
+ state->SetInteger("interval_us", interval_.InMicroseconds());
+ return state.PassAs<base::Value>();
+ }
+
+ protected:
+ virtual std::string GetType() const = 0;
+
+ base::TimeDelta interval_;
+ FrameSink* sink_;
+};
+
+/**
+ * A frame source which proxies BeginFrame from an external OutputSurface such
+ * as on Android.
+ */
+class ExternalFrameSource : public FrameSource {
+ public:
+ ExternalFrameSource(FrameSink* sink, SchedulerClient* client)
+ : client_(client), FrameSource(sink) {
+ DCHECK(client_);
+ }
+ virtual ~ExternalFrameSource() {}
+
+ virtual void BeginFrame(BeginFrameArgs* args) { sink_->BeginFrame(args); }
+
+ virtual void SetNeedsBeginFrame(bool needs_begin_frame) OVERRIDE {
+ DCHECK(client_);
+ client_->SetNeedsBeginFrame(needs_begin_frame);
+ }
+
+ virtual scoped_ptr<base::Value> AsValue() const OVERRIDE {
+ scoped_ptr<base::DictionaryValue> state = FrameSource::AsValue();
+ state->SetInteger("client", client_);
+ return state.PassAs<base::Value>();
+ }
+
+ protected:
+ virtual std::string GetType() const OVERRIDE { return "ExternalFrameSource"; }
+
+ private:
+ SchedulerClient* client_;
+};
+
+/**
+ * A frame source which throttles down another begin frame source.
+ */
+class ThrottledFrameSource : public FrameSource, FrameSink {
brianderson 2014/05/05 16:50:05 In what cases would this class be used? Is this to
mithro-old 2014/05/05 17:10:53 Yes, examples I can think of are; * Throttle an E
brianderson 2014/05/05 17:37:49 Cool. What would the interface look like to change
+ public:
+ ThrottledFrameSource(FrameSink* sink,
+ const scoped_refptr<FrameSource>& source,
+ base::TimeDelta interval)
+ : source_(source),
+ interval_(interval),
+ last_frame_args_(),
+ FrameSource(sink) {
+ source_->SetSink(this);
+ }
+ virtual ~ThrottledFrameSource() {}
+
+ virtual void BeginFrame(BeginFrameArgs* args) OVERRIDE {
+ if (last_frame_args_.frame_time + interval_ > args.frame_time)
+ return;
+ source_->SendBeginFrame(sink, args);
+ }
+
+ virtual void SetNeedsBeginFrame(bool needs_begin_frame) OVERRIDE {
+ source_->SetNeedsBeginFrame(needs_begin_frame);
+ }
+
+ virtual scoped_ptr<base::Value> AsValue() const OVERRIDE {
+ scoped_ptr<base::DictionaryValue> state = FrameSource::AsValue();
+ state->SetValue("source", source_->AsValue().release());
+ return state.PassAs<base::Value>();
+ }
+
+ protected:
+ virtual std::string GetType() const OVERRIDE {
+ return "ThrottledFrameSource";
+ }
+
+ private:
+ BeginFrameArgs last_frame_args_;
+ scoped_refptr<base::FrameSource> source_;
+};
+
+/**
+ * Frame source which needs a task runner object.
+ */
+class TaskRunnerFrameSource : public FrameSource {
+ public:
+ TaskRunnerFrameSource(FrameSink* sink,
+ base::SingleThreadTaskRunner* task_runner)
+ : task_runner_(task_runner), FrameSource(sink) {
+ DCHECK(task_runner);
+ }
+ virtual ~TaskRunnerFrameSource() {}
+
+ protected:
+ base::SingleThreadTaskRunner task_runner_;
+};
+
+/**
+ * A frame source which sends a BeginFrame as soon as SetNeedsBeginFrame is
+ * requested.
+ */
+class BackToBackFrameSource : public TaskRunnerFrameSource {
brianderson 2014/05/05 16:50:05 Would this be used as the "vsync disabled" BeginFr
mithro-old 2014/05/05 17:10:53 Is there any reason we want to keep it level trigg
brianderson 2014/05/05 17:37:49 It is level triggered at the interface between the
+ public:
+ virtual void SetNeedsBeginFrame(bool needs_begin_frame) OVERRIDE {
+ if (needs_begin_frame) {
+ task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&BackToBackFrameSource::PostBeginFrame,
+ weak_factory_.GetWeakPtr()));
+ }
+ }
+
+ void PostBeginFrame() {
+ base::TimeTicks now = gfx::FrameTime::Now();
+ BeginFrameArgs begin_frame_args =
+ BeginFrameArgs::Create(now, base::TimeTicks(), base::TimeDelta());
+ FrameSource::SendBeginFrame(args);
+ }
+
+ protected:
+ virtual std::string GetType() const OVERRIDE {
+ return "BackToBackFrameSource";
+ }
+};
+
+/**
+ * A frame source which is locked an external vsync source and generates
+ * BeginFrameArgs for it.
+ */
+class SyntheticFrameSource : public TaskRunnerFrameSource,
+ public TimeSourceClient {
+ public:
+ SyntheticFrameSource(FrameSink* sink,
+ base::SingleThreadTaskRunner* task_runner)
+ : TaskRunnerFrameSource(sink, task_runner) {
+ if (gfx::FrameTime::TimestampsAreHighRes()) {
+ time_source_ = DelayBasedTimeSourceHighRes::Create(sink_->VSyncInterval(),
+ task_runner);
+ } else {
+ time_source_ =
+ DelayBasedTimeSource::Create(sink_->VSyncInterval(), task_runner);
+ }
+ time_source_->SetClient(this);
+ }
+ virtual ~SyntheticFrameSource() {}
+
+ // Activates future BeginFrames and, if activating, pushes the most
+ // recently missed BeginFrame to the back of a retroactive queue.
+ void SetNeedsBeginFrame(bool needs_begin_frame) OVERRIDE {
+ base::TimeTicks missed_tick_time =
+ time_source_->SetActive(needs_begin_frame);
+ if (!missed_tick_time.is_null()) {
+ BaseFrameSource::SendBeginFrame(
+ CreateSyntheticBeginFrameArgs(missed_tick_time));
+ }
+ }
+
+ // Updates the phase and frequency of the timer.
+ virtual void UpdateFrameSource(base::TimeTicks timebase,
+ base::TimeDelta interval) OVERRIDE {
+ TaskRunnerFrameSource::UpdateFrameSource(timebase, interval);
+ time_source_->SetTimebaseAndInterval(timebase, interval);
+ }
+
+ virtual scoped_ptr<base::Value> AsValue() const OVERRIDE {
+ scoped_ptr<base::DictionaryValue> state = FrameSource::AsValue();
+ state->SetValue("source", source_->AsValue().release());
+ return state.PassAs<base::Value>();
+ }
+
+ // TimeSourceClient implementation of OnTimerTick triggers a BeginFrame.
+ virtual void OnTimerTick() OVERRIDE {
+ BeginFrameArgs begin_frame_args(
+ CreateSyntheticBeginFrameArgs(time_source_->LastTickTime()));
+ SendBeginFrame(begin_frame_args);
+ }
+
+ protected:
+ virtual std::string GetType() const OVERRIDE {
+ return "SyntheticFrameSource";
+ }
+
+ private:
+ FrameSink* sink_;
+ scoped_refptr<TimeSource> time_source_;
+
+ BeginFrameArgs CreateSyntheticBeginFrameArgs(base::TimeTicks frame_time) {
+ base::TimeTicks deadline =
+ time_source_->NextTickTime() - sink_->EstimatedParentDrawTime();
+ return BeginFrameArgs::Create(frame_time, deadline, interval_);
+ }
+};
+
+/**
+ * A virtual frame source which lets you switch between two other frame sources
+ * (making sure the BeginFrameArgs stays monotonic).
+ */
+class DualFrameSource : public FrameSource, public FrameSink {
brianderson 2014/05/05 16:50:05 Is this going to be used to switch between backgro
mithro-old 2014/05/05 17:10:53 Yeah. The thought here was to allow switching betw
+ public:
+ DualFrameSource(FrameSink* sink,
+ const scoped_refptr<FrameSource>& source_primary,
+ const scoped_refptr<FrameSource>& source_secondary)
+ : source_primary_(source_primary),
+ source_secondary_(source_secondary),
+ needs_begin_frame_(false),
+ last_frame_args_() {
+ source_primary_->SetSink(this);
+ source_secondary_->SetSink(this);
+ SwitchSource(SourcePrimary());
+ }
+
+ virtual void BeginFrame(BeginFrameArgs* args) OVERRIDE {
+ // When switching clock sources you can get a BeginFrameArgs with a
+ // frame_time before the last value.
+ if (last_frame_args_.frame_time > args.frame_time)
+ args.frame_time = last_frame_args_.frame_time;
+
+ FrameSource::SendBeginFrame(args);
+ last_frame_args_ = args;
+ }
+
+ virtual void SetNeedsBeginFrame(bool needs_begin_frame) OVERRIDE {
+ DCHECK(active_source_);
+ needs_begin_frame_ = needs_begin_frame;
+ active_source_->SetNeedsBeginFrame(needs_begin_frame);
+ }
+
+ virtual scoped_ptr<base::Value> AsValue() const OVERRIDE {
+ scoped_ptr<base::DictionaryValue> state = FrameSource::AsValue();
+ if (active_source_ == SourcePrimary())
+ state->SetString("active", "primary");
+ if (active_source_ == SourceSecondary())
+ state->SetString("active", "secondary");
+ state->SetValue("primary", source_primary_->AsValue().release());
+ state->SetValue("secondary", source_secondary_->AsValue().release());
+ state->SetValue("last_frame_args", last_frame_args_->AsValue().release());
+ return state.PassAs<base::Value>();
+ }
+
+ // ---------------------------------------------------------------------
+
+ void SwitchSource(base::FrameSource* new_source) {
+ DCHECK(new_source == SourcePrimary() || new_source == SourceSecondary());
+
+ if (needs_begin_frame_)
+ active_source_.SetNeedsBeginFrame(false);
+
+ active_source_ = new_source;
+
+ if (needs_begin_frame_)
+ active_source_.SetNeedsBeginFrame(true);
+ }
+
+ base::FrameSource* SourcePrimary() { return source_primary_.get(); }
+
+ base::FrameSource* SourceSecondary() { return source_secondary_.get(); }
+
+ protected:
+ virtual std::string GetType() const OVERRIDE {
+ return std::string("DualFrameSource");
+ }
+
+ private:
+ bool needs_begin_frame_;
+ BeginFrameArgs last_frame_args_;
+ base::FrameSource* active_source_;
+ scoped_refptr<base::FrameSource> source_primary_;
+ scoped_refptr<base::FrameSource> source_secondary_;
+};
+
+} // namespace cc
« no previous file with comments | « cc/output/begin_frame_args.h ('k') | cc/scheduler/scheduler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698