| Index: cc/scheduler/scheduler.cc
|
| diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
|
| index e98f96689e16f247bf23482997264bb49bb8db9c..c78bf3a92d180a3ba03f0db551990a667a55db95 100644
|
| --- a/cc/scheduler/scheduler.cc
|
| +++ b/cc/scheduler/scheduler.cc
|
| @@ -17,69 +17,73 @@
|
|
|
| namespace cc {
|
|
|
| -Scheduler::SyntheticBeginFrameSource::SyntheticBeginFrameSource(
|
| - Scheduler* scheduler,
|
| - scoped_refptr<DelayBasedTimeSource> time_source)
|
| - : scheduler_(scheduler), time_source_(time_source) {
|
| - time_source_->SetClient(this);
|
| -}
|
| -
|
| -Scheduler::SyntheticBeginFrameSource::~SyntheticBeginFrameSource() {
|
| -}
|
| -
|
| -void Scheduler::SyntheticBeginFrameSource::CommitVSyncParameters(
|
| - base::TimeTicks timebase,
|
| - base::TimeDelta interval) {
|
| - time_source_->SetTimebaseAndInterval(timebase, interval);
|
| -}
|
| -
|
| -void Scheduler::SyntheticBeginFrameSource::SetNeedsBeginFrame(
|
| - bool needs_begin_frame,
|
| - std::deque<BeginFrameArgs>* begin_retro_frame_args) {
|
| - DCHECK(begin_retro_frame_args);
|
| - base::TimeTicks missed_tick_time =
|
| - time_source_->SetActive(needs_begin_frame);
|
| - if (!missed_tick_time.is_null()) {
|
| - begin_retro_frame_args->push_back(
|
| - CreateSyntheticBeginFrameArgs(missed_tick_time));
|
| +BeginFrameSource* SchedulerFrameSourcesConstructor::ConstructPrimaryFrameSource(
|
| + Scheduler* scheduler) {
|
| + if (!scheduler->settings_.throttle_frame_production) {
|
| + TRACE_EVENT1("cc",
|
| + "Scheduler::Scheduler()",
|
| + "PrimaryFrameSource",
|
| + "BackToBackBeginFrameSource");
|
| + DCHECK(!scheduler->primary_frame_source_internal_);
|
| + scheduler->primary_frame_source_internal_ =
|
| + BackToBackBeginFrameSource::Create(scheduler->task_runner_.get());
|
| + return scheduler->primary_frame_source_internal_.get();
|
| + } else if (scheduler->settings_.begin_frame_scheduling_enabled) {
|
| + TRACE_EVENT1("cc",
|
| + "Scheduler::Scheduler()",
|
| + "PrimaryFrameSource",
|
| + "SchedulerClient");
|
| + return scheduler->client_->ExternalBeginFrameSource();
|
| + } else {
|
| + TRACE_EVENT1("cc",
|
| + "Scheduler::Scheduler()",
|
| + "PrimaryFrameSource",
|
| + "SyntheticBeginFrameSource");
|
| + scoped_ptr<SyntheticBeginFrameSource> synthetic_source =
|
| + SyntheticBeginFrameSource::Create(scheduler->task_runner_.get(),
|
| + scheduler->Now(),
|
| + BeginFrameArgs::DefaultInterval());
|
| +
|
| + DCHECK(!scheduler->vsync_observer_);
|
| + scheduler->vsync_observer_ = synthetic_source.get();
|
| +
|
| + DCHECK(!scheduler->primary_frame_source_internal_);
|
| + scheduler->primary_frame_source_internal_ = synthetic_source.Pass();
|
| + return scheduler->primary_frame_source_internal_.get();
|
| }
|
| }
|
|
|
| -bool Scheduler::SyntheticBeginFrameSource::IsActive() const {
|
| - return time_source_->Active();
|
| -}
|
| -
|
| -void Scheduler::SyntheticBeginFrameSource::OnTimerTick() {
|
| - BeginFrameArgs begin_frame_args(
|
| - CreateSyntheticBeginFrameArgs(time_source_->LastTickTime()));
|
| - scheduler_->BeginFrame(begin_frame_args);
|
| -}
|
| -
|
| -void Scheduler::SyntheticBeginFrameSource::AsValueInto(
|
| - base::debug::TracedValue* state) const {
|
| - time_source_->AsValueInto(state);
|
| -}
|
| -
|
| -BeginFrameArgs
|
| -Scheduler::SyntheticBeginFrameSource::CreateSyntheticBeginFrameArgs(
|
| - base::TimeTicks frame_time) {
|
| - base::TimeTicks deadline = time_source_->NextTickTime();
|
| - return BeginFrameArgs::Create(
|
| - frame_time, deadline, scheduler_->VSyncInterval());
|
| +BeginFrameSource*
|
| +SchedulerFrameSourcesConstructor::ConstructBackgroundFrameSource(
|
| + Scheduler* scheduler) {
|
| + TRACE_EVENT1("cc",
|
| + "Scheduler::Scheduler()",
|
| + "BackgroundFrameSource",
|
| + "SyntheticBeginFrameSource");
|
| + DCHECK(!(scheduler->background_frame_source_internal_));
|
| + scheduler->background_frame_source_internal_ =
|
| + SyntheticBeginFrameSource::Create(scheduler->task_runner_.get(),
|
| + scheduler->Now(),
|
| + base::TimeDelta::FromSeconds(1));
|
| + return scheduler->background_frame_source_internal_.get();
|
| }
|
|
|
| Scheduler::Scheduler(
|
| SchedulerClient* client,
|
| const SchedulerSettings& scheduler_settings,
|
| int layer_tree_host_id,
|
| - const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
|
| - : settings_(scheduler_settings),
|
| + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
|
| + SchedulerFrameSourcesConstructor* frame_sources_constructor)
|
| + : frame_source_(),
|
| + primary_frame_source_(NULL),
|
| + background_frame_source_(NULL),
|
| + primary_frame_source_internal_(),
|
| + background_frame_source_internal_(),
|
| + vsync_observer_(NULL),
|
| + settings_(scheduler_settings),
|
| client_(client),
|
| layer_tree_host_id_(layer_tree_host_id),
|
| task_runner_(task_runner),
|
| - vsync_interval_(BeginFrameArgs::DefaultInterval()),
|
| - last_set_needs_begin_frame_(false),
|
| - begin_unthrottled_frame_posted_(false),
|
| begin_retro_frame_posted_(false),
|
| state_machine_(scheduler_settings),
|
| inside_process_scheduled_actions_(false),
|
| @@ -97,8 +101,6 @@ Scheduler::Scheduler(
|
|
|
| begin_retro_frame_closure_ =
|
| base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr());
|
| - begin_unthrottled_frame_closure_ =
|
| - base::Bind(&Scheduler::BeginUnthrottledFrame, weak_factory_.GetWeakPtr());
|
| begin_impl_frame_deadline_closure_ = base::Bind(
|
| &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr());
|
| poll_for_draw_triggers_closure_ = base::Bind(
|
| @@ -106,34 +108,30 @@ Scheduler::Scheduler(
|
| advance_commit_state_closure_ = base::Bind(
|
| &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr());
|
|
|
| - if (!settings_.begin_frame_scheduling_enabled) {
|
| - SetupSyntheticBeginFrames();
|
| - }
|
| -}
|
| + frame_source_ = BeginFrameSourceMultiplexer::Create();
|
| + frame_source_->AddObserver(this);
|
|
|
| -Scheduler::~Scheduler() {
|
| - if (synthetic_begin_frame_source_) {
|
| - synthetic_begin_frame_source_->SetNeedsBeginFrame(false,
|
| - &begin_retro_frame_args_);
|
| - }
|
| + // Primary frame source
|
| + primary_frame_source_ =
|
| + frame_sources_constructor->ConstructPrimaryFrameSource(this);
|
| + frame_source_->AddSource(primary_frame_source_);
|
| +
|
| + // Background ticking frame source
|
| + background_frame_source_ =
|
| + frame_sources_constructor->ConstructBackgroundFrameSource(this);
|
| + frame_source_->AddSource(background_frame_source_);
|
| }
|
|
|
| -void Scheduler::SetupSyntheticBeginFrames() {
|
| - scoped_refptr<DelayBasedTimeSource> time_source;
|
| - if (gfx::FrameTime::TimestampsAreHighRes()) {
|
| - time_source = DelayBasedTimeSourceHighRes::Create(VSyncInterval(),
|
| - task_runner_.get());
|
| - } else {
|
| - time_source =
|
| - DelayBasedTimeSource::Create(VSyncInterval(), task_runner_.get());
|
| - }
|
| - DCHECK(!synthetic_begin_frame_source_);
|
| - synthetic_begin_frame_source_.reset(
|
| - new SyntheticBeginFrameSource(this, time_source));
|
| +Scheduler::~Scheduler() {
|
| }
|
|
|
| base::TimeTicks Scheduler::Now() const {
|
| - return gfx::FrameTime::Now();
|
| + base::TimeTicks now = gfx::FrameTime::Now();
|
| + TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.now"),
|
| + "Scheduler::Now",
|
| + "now",
|
| + now);
|
| + return now;
|
| }
|
|
|
| void Scheduler::CommitVSyncParameters(base::TimeTicks timebase,
|
| @@ -141,9 +139,9 @@ void Scheduler::CommitVSyncParameters(base::TimeTicks timebase,
|
| // TODO(brianderson): We should not be receiving 0 intervals.
|
| if (interval == base::TimeDelta())
|
| interval = BeginFrameArgs::DefaultInterval();
|
| - vsync_interval_ = interval;
|
| - if (!settings_.begin_frame_scheduling_enabled)
|
| - synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval);
|
| +
|
| + if (vsync_observer_)
|
| + vsync_observer_->OnUpdateVSyncParameters(timebase, interval);
|
| }
|
|
|
| void Scheduler::SetEstimatedParentDrawTime(base::TimeDelta draw_time) {
|
| @@ -158,6 +156,11 @@ void Scheduler::SetCanStart() {
|
|
|
| void Scheduler::SetVisible(bool visible) {
|
| state_machine_.SetVisible(visible);
|
| + if (visible) {
|
| + frame_source_->SetActiveSource(primary_frame_source_);
|
| + } else {
|
| + frame_source_->SetActiveSource(background_frame_source_);
|
| + }
|
| ProcessScheduledActions();
|
| }
|
|
|
| @@ -240,18 +243,15 @@ void Scheduler::DidManageTiles() {
|
| void Scheduler::DidLoseOutputSurface() {
|
| TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface");
|
| state_machine_.DidLoseOutputSurface();
|
| - last_set_needs_begin_frame_ = false;
|
| - if (!settings_.begin_frame_scheduling_enabled) {
|
| - synthetic_begin_frame_source_->SetNeedsBeginFrame(false,
|
| - &begin_retro_frame_args_);
|
| - }
|
| + if (frame_source_->NeedsBeginFrames())
|
| + frame_source_->SetNeedsBeginFrames(false);
|
| begin_retro_frame_args_.clear();
|
| ProcessScheduledActions();
|
| }
|
|
|
| void Scheduler::DidCreateAndInitializeOutputSurface() {
|
| TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface");
|
| - DCHECK(!last_set_needs_begin_frame_);
|
| + DCHECK(!frame_source_->NeedsBeginFrames());
|
| DCHECK(begin_impl_frame_deadline_task_.IsCancelled());
|
| state_machine_.DidCreateAndInitializeOutputSurface();
|
| ProcessScheduledActions();
|
| @@ -263,7 +263,7 @@ void Scheduler::NotifyBeginMainFrameStarted() {
|
| }
|
|
|
| base::TimeTicks Scheduler::AnticipatedDrawTime() const {
|
| - if (!last_set_needs_begin_frame_ ||
|
| + if (!frame_source_->NeedsBeginFrames() ||
|
| begin_impl_frame_args_.interval <= base::TimeDelta())
|
| return base::TimeTicks();
|
|
|
| @@ -284,75 +284,27 @@ void Scheduler::SetupNextBeginFrameIfNeeded() {
|
|
|
| bool needs_begin_frame = state_machine_.BeginFrameNeeded();
|
|
|
| - if (settings_.throttle_frame_production) {
|
| - SetupNextBeginFrameWhenVSyncThrottlingEnabled(needs_begin_frame);
|
| - } else {
|
| - SetupNextBeginFrameWhenVSyncThrottlingDisabled(needs_begin_frame);
|
| - }
|
| - SetupPollingMechanisms(needs_begin_frame);
|
| -}
|
| -
|
| -// When we are throttling frame production, we request BeginFrames
|
| -// from the OutputSurface.
|
| -void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingEnabled(
|
| - bool needs_begin_frame) {
|
| bool at_end_of_deadline =
|
| - state_machine_.begin_impl_frame_state() ==
|
| - SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE;
|
| + (state_machine_.begin_impl_frame_state() ==
|
| + SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE);
|
|
|
| bool should_call_set_needs_begin_frame =
|
| // Always request the BeginFrame immediately if it wasn't needed before.
|
| - (needs_begin_frame && !last_set_needs_begin_frame_) ||
|
| + (needs_begin_frame && !frame_source_->NeedsBeginFrames()) ||
|
| // Only stop requesting BeginFrames after a deadline.
|
| - (!needs_begin_frame && last_set_needs_begin_frame_ && at_end_of_deadline);
|
| + (!needs_begin_frame && frame_source_->NeedsBeginFrames() &&
|
| + at_end_of_deadline);
|
|
|
| if (should_call_set_needs_begin_frame) {
|
| - if (settings_.begin_frame_scheduling_enabled) {
|
| - client_->SetNeedsBeginFrame(needs_begin_frame);
|
| - } else {
|
| - synthetic_begin_frame_source_->SetNeedsBeginFrame(
|
| - needs_begin_frame, &begin_retro_frame_args_);
|
| - }
|
| - last_set_needs_begin_frame_ = needs_begin_frame;
|
| + frame_source_->SetNeedsBeginFrames(needs_begin_frame);
|
| }
|
|
|
| - PostBeginRetroFrameIfNeeded();
|
| -}
|
| -
|
| -// When we aren't throttling frame production, we initiate a BeginFrame
|
| -// as soon as one is needed.
|
| -void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingDisabled(
|
| - bool needs_begin_frame) {
|
| - last_set_needs_begin_frame_ = needs_begin_frame;
|
| -
|
| - if (!needs_begin_frame || begin_unthrottled_frame_posted_)
|
| - return;
|
| -
|
| - if (state_machine_.begin_impl_frame_state() !=
|
| - SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE &&
|
| - state_machine_.begin_impl_frame_state() !=
|
| - SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) {
|
| - return;
|
| + if (at_end_of_deadline) {
|
| + frame_source_->DidFinishFrame(begin_retro_frame_args_.size());
|
| }
|
|
|
| - begin_unthrottled_frame_posted_ = true;
|
| - task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_);
|
| -}
|
| -
|
| -// BeginUnthrottledFrame is used when we aren't throttling frame production.
|
| -// This will usually be because VSync is disabled.
|
| -void Scheduler::BeginUnthrottledFrame() {
|
| - DCHECK(!settings_.throttle_frame_production);
|
| - DCHECK(begin_retro_frame_args_.empty());
|
| -
|
| - base::TimeTicks now = Now();
|
| - base::TimeTicks deadline = now + vsync_interval_;
|
| -
|
| - BeginFrameArgs begin_frame_args =
|
| - BeginFrameArgs::Create(now, deadline, vsync_interval_);
|
| - BeginImplFrame(begin_frame_args);
|
| -
|
| - begin_unthrottled_frame_posted_ = false;
|
| + PostBeginRetroFrameIfNeeded();
|
| + SetupPollingMechanisms(needs_begin_frame);
|
| }
|
|
|
| // We may need to poll when we can't rely on BeginFrame to advance certain
|
| @@ -408,9 +360,18 @@ void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) {
|
| // making a frame. Usually this means that user input for the frame is complete.
|
| // If the scheduler is busy, we queue the BeginFrame to be handled later as
|
| // a BeginRetroFrame.
|
| -void Scheduler::BeginFrame(const BeginFrameArgs& args) {
|
| +bool Scheduler::OnBeginFrameMixInDelegate(const BeginFrameArgs& args) {
|
| TRACE_EVENT1("cc", "Scheduler::BeginFrame", "args", args.AsValue());
|
| - DCHECK(settings_.throttle_frame_production);
|
| +
|
| + // We have just called SetNeedsBeginFrame(true) and the BeginFrameSource has
|
| + // sent us the last BeginFrame we have missed. As we might not be able to
|
| + // actually make rendering for this call, handle it like a "retro frame".
|
| + // TODO(brainderson): Add a test for this functionality ASAP!
|
| + if (args.type == BeginFrameArgs::MISSED) {
|
| + begin_retro_frame_args_.push_back(args);
|
| + PostBeginRetroFrameIfNeeded();
|
| + return true;
|
| + }
|
|
|
| BeginFrameArgs adjusted_args(args);
|
| adjusted_args.deadline -= EstimatedParentDrawTime();
|
| @@ -421,7 +382,7 @@ void Scheduler::BeginFrame(const BeginFrameArgs& args) {
|
| } else {
|
| should_defer_begin_frame =
|
| !begin_retro_frame_args_.empty() || begin_retro_frame_posted_ ||
|
| - !last_set_needs_begin_frame_ ||
|
| + !frame_source_->NeedsBeginFrames() ||
|
| (state_machine_.begin_impl_frame_state() !=
|
| SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
|
| }
|
| @@ -430,10 +391,11 @@ void Scheduler::BeginFrame(const BeginFrameArgs& args) {
|
| begin_retro_frame_args_.push_back(adjusted_args);
|
| TRACE_EVENT_INSTANT0(
|
| "cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD);
|
| - return;
|
| + // Queuing the frame counts as "using it", so we need to return true.
|
| + } else {
|
| + BeginImplFrame(adjusted_args);
|
| }
|
| -
|
| - BeginImplFrame(adjusted_args);
|
| + return true;
|
| }
|
|
|
| // BeginRetroFrame is called for BeginFrames that we've deferred because
|
| @@ -472,10 +434,10 @@ void Scheduler::BeginRetroFrame() {
|
| "BeginFrameArgs",
|
| begin_retro_frame_args_.front().AsValue());
|
| begin_retro_frame_args_.pop_front();
|
| + frame_source_->DidFinishFrame(begin_retro_frame_args_.size());
|
| }
|
|
|
| if (begin_retro_frame_args_.empty()) {
|
| - DCHECK(settings_.throttle_frame_production);
|
| TRACE_EVENT_INSTANT0("cc",
|
| "Scheduler::BeginRetroFrames all expired",
|
| TRACE_EVENT_SCOPE_THREAD);
|
| @@ -494,7 +456,7 @@ void Scheduler::PostBeginRetroFrameIfNeeded() {
|
| "Scheduler::PostBeginRetroFrameIfNeeded",
|
| "state",
|
| AsValue());
|
| - if (!last_set_needs_begin_frame_)
|
| + if (!frame_source_->NeedsBeginFrames())
|
| return;
|
|
|
| if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_)
|
| @@ -712,21 +674,18 @@ void Scheduler::AsValueInto(base::debug::TracedValue* state) const {
|
| state->BeginDictionary("state_machine");
|
| state_machine_.AsValueInto(state, Now());
|
| state->EndDictionary();
|
| - if (synthetic_begin_frame_source_) {
|
| - state->BeginDictionary("synthetic_begin_frame_source_");
|
| - synthetic_begin_frame_source_->AsValueInto(state);
|
| - state->EndDictionary();
|
| - }
|
| +
|
| + state->BeginDictionary("frame_source_");
|
| + frame_source_->AsValueInto(state);
|
| + state->EndDictionary();
|
|
|
| state->BeginDictionary("scheduler_state");
|
| state->SetDouble("time_until_anticipated_draw_time_ms",
|
| (AnticipatedDrawTime() - Now()).InMillisecondsF());
|
| - state->SetDouble("vsync_interval_ms", vsync_interval_.InMillisecondsF());
|
| state->SetDouble("estimated_parent_draw_time_ms",
|
| estimated_parent_draw_time_.InMillisecondsF());
|
| - state->SetBoolean("last_set_needs_begin_frame_", last_set_needs_begin_frame_);
|
| - state->SetBoolean("begin_unthrottled_frame_posted_",
|
| - begin_unthrottled_frame_posted_);
|
| + state->SetBoolean("last_set_needs_begin_frame_",
|
| + frame_source_->NeedsBeginFrames());
|
| state->SetBoolean("begin_retro_frame_posted_", begin_retro_frame_posted_);
|
| state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size());
|
| state->SetBoolean("begin_impl_frame_deadline_task_",
|
|
|