Chromium Code Reviews| Index: cc/scheduler/frame_source.cc |
| diff --git a/cc/scheduler/frame_source.cc b/cc/scheduler/frame_source.cc |
| index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..48365d0071cd87f35342f91e2d4d5e48745ed1ba 100644 |
| --- a/cc/scheduler/frame_source.cc |
| +++ b/cc/scheduler/frame_source.cc |
| @@ -0,0 +1,355 @@ |
| +// 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" |
|
simonhong
2014/06/12 13:47:39
All above includes are duplicated with frame_sourc
|
| +#include "cc/scheduler/scheduler.h" |
|
simonhong
2014/06/12 13:47:39
Scheduler class is not referenced in this file.
Ca
|
| +#include "ui/gfx/frame_time.h" |
|
simonhong
2014/06/12 13:47:38
ditto.
|
| + |
| +#define FRAMESOURCE_TYPESTRING(x) \ |
| + std::string x::TypeString() const { return #x; } |
| + |
| +namespace cc { |
| + |
| +BaseBeginFrameSource::BaseBeginFrameSource(BeginFrameSink* sink) |
| + : frame_sink_(sink), |
| + generate_frames_(false), |
| + timebase_(), |
|
simonhong
2014/06/12 13:47:39
can be removed.
|
| + 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_); |
|
simonhong
2014/06/12 13:47:39
DCHECK can be removed because we don't erase or ch
|
| + source_->SetGenerateFrames(generate_frames); |
| +} |
| + |
| +void ProxyBeginFrameSource::OnPendingFrames(size_t count) { |
| + DCHECK(source_); |
|
simonhong
2014/06/12 13:47:39
ditto.
|
| + source_->PendingFrames(count); |
| +} |
| + |
| +void ProxyBeginFrameSource::OnTimeBaseAndIntervalChange( |
| + const base::TimeTicks timebase, |
| + const base::TimeDelta interval) { |
| + DCHECK(source_); |
|
simonhong
2014/06/12 13:47:39
ditto.
|
| + 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), |
| + weak_factory_(this), |
| + task_runner_(task_runner), |
| + send_begin_frame_posted_(false) { |
| + DCHECK(task_runner); |
| +} |
| + |
| +BackToBackBeginFrameSource::~BackToBackBeginFrameSource() { |
| +} |
| + |
| +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, |
| + weak_factory_.GetWeakPtr())); |
| +} |
| + |
| +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); |
|
simonhong
2014/06/12 13:47:39
time_source_ is set to inactive when it is initial
|
| + 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()) { |
|
simonhong
2014/06/12 13:47:38
Generally, curly braces are not required for singl
|
| + 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 |