Index: cc/scheduler/scheduler.cc |
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc |
index e98f96689e16f247bf23482997264bb49bb8db9c..4ab8dfd4474490014f975711ac74d563d4958566 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,8 @@ 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()); |
simonhong
2014/09/25 06:19:46
"Scheduler::OnBeginFrameMixInDelegate"?
|
- DCHECK(settings_.throttle_frame_production); |
BeginFrameArgs adjusted_args(args); |
adjusted_args.deadline -= EstimatedParentDrawTime(); |
@@ -421,7 +372,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 +381,21 @@ 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); |
} |
+ return true; |
+} |
- BeginImplFrame(adjusted_args); |
+// 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! |
+bool Scheduler::OnMissedBeginFrameMixInDelegate(const BeginFrameArgs& args) { |
+ begin_retro_frame_args_.push_back(args); |
+ PostBeginRetroFrameIfNeeded(); |
+ 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_", |