Index: cc/scheduler/scheduler.cc |
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc |
index 7f0232d3d306a9c9ca51ab198c5b37b61db66561..1df91bb60412c8cb28ed69a5047d97c1bb625ed6 100644 |
--- a/cc/scheduler/scheduler.cc |
+++ b/cc/scheduler/scheduler.cc |
@@ -90,7 +90,7 @@ Scheduler::Scheduler( |
layer_tree_host_id_(layer_tree_host_id), |
task_runner_(task_runner), |
power_monitor_(power_monitor), |
- begin_retro_frame_posted_(false), |
+ begin_frame_process_posted_(false), |
state_machine_(scheduler_settings), |
inside_process_scheduled_actions_(false), |
inside_action_(SchedulerStateMachine::ACTION_NONE), |
@@ -102,8 +102,8 @@ Scheduler::Scheduler( |
DCHECK(client_); |
DCHECK(!state_machine_.BeginFrameNeeded()); |
- begin_retro_frame_closure_ = |
- base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr()); |
+ begin_frame_process_closure_ = |
+ base::Bind(&Scheduler::ProcessBeginFrames, weak_factory_.GetWeakPtr()); |
begin_impl_frame_deadline_closure_ = base::Bind( |
&Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr()); |
poll_for_draw_triggers_closure_ = base::Bind( |
@@ -159,11 +159,6 @@ void Scheduler::TeardownPowerMonitoring() { |
} |
} |
-void Scheduler::OnPowerStateChange(bool on_battery_power) { |
- DCHECK(settings_.disable_hi_res_timer_tasks_on_battery); |
- state_machine_.SetImplLatencyTakesPriorityOnBattery(on_battery_power); |
-} |
- |
void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, |
base::TimeDelta interval) { |
// TODO(brianderson): We should not be receiving 0 intervals. |
@@ -249,11 +244,6 @@ void Scheduler::DidSwapBuffersComplete() { |
ProcessScheduledActions(); |
} |
-void Scheduler::SetImplLatencyTakesPriority(bool impl_latency_takes_priority) { |
- state_machine_.SetImplLatencyTakesPriority(impl_latency_takes_priority); |
- ProcessScheduledActions(); |
-} |
- |
void Scheduler::NotifyReadyToCommit() { |
TRACE_EVENT0("cc", "Scheduler::NotifyReadyToCommit"); |
state_machine_.NotifyReadyToCommit(); |
@@ -275,7 +265,7 @@ void Scheduler::DidLoseOutputSurface() { |
state_machine_.DidLoseOutputSurface(); |
if (frame_source_->NeedsBeginFrames()) |
frame_source_->SetNeedsBeginFrames(false); |
- begin_retro_frame_args_.clear(); |
+ pending_begin_frame_args_.clear(); |
ProcessScheduledActions(); |
} |
@@ -283,8 +273,17 @@ void Scheduler::DidCreateAndInitializeOutputSurface() { |
TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); |
DCHECK(!frame_source_->NeedsBeginFrames()); |
DCHECK(begin_impl_frame_deadline_task_.IsCancelled()); |
+ |
state_machine_.DidCreateAndInitializeOutputSurface(); |
ProcessScheduledActions(); |
+ |
+ // We want to start the first commit ASAP, so we post the LastBeginFrameArgs |
+ // onto the retro queue and process it. |
+ BeginFrameArgs missed = frame_source_->LastBeginFrameArgs(); |
+ missed.type = BeginFrameArgs::MISSED; |
+ // Adjust the deadline |
+ //missed.deadline = XXXXX |
+ OnBeginFrame(missed); |
} |
void Scheduler::NotifyBeginMainFrameStarted() { |
@@ -292,22 +291,6 @@ void Scheduler::NotifyBeginMainFrameStarted() { |
state_machine_.NotifyBeginMainFrameStarted(); |
} |
-base::TimeTicks Scheduler::AnticipatedDrawTime() const { |
- if (!frame_source_->NeedsBeginFrames() || |
- begin_impl_frame_args_.interval <= base::TimeDelta()) |
- return base::TimeTicks(); |
- |
- base::TimeTicks now = Now(); |
- base::TimeTicks timebase = std::max(begin_impl_frame_args_.frame_time, |
- begin_impl_frame_args_.deadline); |
- int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval); |
- return timebase + (begin_impl_frame_args_.interval * intervals); |
-} |
- |
-base::TimeTicks Scheduler::LastBeginImplFrameTime() { |
- return begin_impl_frame_args_.frame_time; |
-} |
- |
void Scheduler::SetupNextBeginFrameIfNeeded() { |
if (!task_runner_.get()) |
return; |
@@ -330,10 +313,9 @@ void Scheduler::SetupNextBeginFrameIfNeeded() { |
} |
if (at_end_of_deadline) { |
- frame_source_->DidFinishFrame(begin_retro_frame_args_.size()); |
+ frame_source_->DidFinishFrame(pending_begin_frame_args_.size()); |
} |
- PostBeginRetroFrameIfNeeded(); |
SetupPollingMechanisms(needs_begin_frame); |
} |
@@ -386,240 +368,137 @@ void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) { |
} |
} |
-// BeginFrame is the mechanism that tells us that now is a good time to start |
-// 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. |
-bool Scheduler::OnBeginFrameMixInDelegate(const BeginFrameArgs& args) { |
- TRACE_EVENT1("cc", "Scheduler::BeginFrame", "args", args.AsValue()); |
+base::TimeDelta Scheduler::TimeForDrawing() { |
+ return EstimatedParentDrawTime() + client_->DrawDurationEstimate(); |
+} |
- // Deliver BeginFrames to children. |
- if (settings_.forward_begin_frames_to_children && |
- state_machine_.children_need_begin_frames()) { |
- BeginFrameArgs adjusted_args_for_children(args); |
- // Adjust a deadline for child schedulers. |
- // TODO(simonhong): Once we have commitless update, we can get rid of |
- // BeginMainFrameToCommitDurationEstimate() + |
- // CommitToActivateDurationEstimate(). |
- adjusted_args_for_children.deadline -= |
- (client_->BeginMainFrameToCommitDurationEstimate() + |
- client_->CommitToActivateDurationEstimate() + |
- client_->DrawDurationEstimate() + EstimatedParentDrawTime()); |
- client_->SendBeginFramesToChildren(adjusted_args_for_children); |
+base::TimeTicks Scheduler::CalculateDeadline(base::TimeTicks now, const BeginFrameArgs& args) { |
+ // Synchronous renderer should doesn't use deadlines. |
+ if (settings_.using_synchronous_renderer_compositor) { |
+ return base::TimeTicks(); |
} |
- // 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; |
+ base::TimeTicks deadline = args.deadline; |
+ |
+ // Decrease the deadline enough to give drawing enough time to happen. |
+ deadline -= TimeForDrawing(); |
+ |
+ if (false) { //is_low_end()) { |
+ // On low end devices, if we start main thread rendering it can stave us |
+ // of CPU. Hence, if we don't think the main will make this frame we should |
+ // run the impl tasks right now. |
+ base::TimeTicks main_thread_time = |
+ client_->BeginMainFrameToCommitDurationEstimate() + |
+ client_->CommitToActivateDurationEstimate(); |
+ |
+ if (now + main_thread_time > deadline) { |
+ deadline = now; |
+ } |
} |
+ |
+ return deadline; |
+} |
- BeginFrameArgs adjusted_args(args); |
- adjusted_args.deadline -= EstimatedParentDrawTime(); |
+// BeginFrame is the mechanism that tells us that now is a good time to start |
+// making a frame. Usually this means that user input for the frame is complete. |
+bool Scheduler::OnBeginFrameMixInDelegate(const BeginFrameArgs& args) { |
+ TRACE_EVENT1("cc", "Scheduler::BeginFrame", "args", args.AsValue()); |
- bool should_defer_begin_frame; |
- if (settings_.using_synchronous_renderer_compositor) { |
- should_defer_begin_frame = false; |
- } else { |
- should_defer_begin_frame = |
- !begin_retro_frame_args_.empty() || begin_retro_frame_posted_ || |
- !frame_source_->NeedsBeginFrames() || |
- (state_machine_.begin_impl_frame_state() != |
- SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); |
+ // Push the BeginFrame onto a queue for processing. |
+ begin_retro_frame_args.push_back(args); |
+ |
+ // If we aren't already processing frames, start processing now. |
+ if (state_machine_.begin_impl_frame_state() == SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE) { |
+ ProcessBeginFrames(nullptr); |
+ // Otherwise, post a task to process the frames after the current processing |
+ // is finished. |
+ } else if (!begin_frame_process_posted_) { |
+ begin_frame_process_posted_ = true; |
+ task_runner_->PostTask(FROM_HERE, begin_frame_process_closure_, &begin_frame_process_posted_); |
} |
- if (should_defer_begin_frame) { |
- begin_retro_frame_args_.push_back(adjusted_args); |
- TRACE_EVENT_INSTANT0( |
- "cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD); |
- // Queuing the frame counts as "using it", so we need to return true. |
- } else { |
- BeginImplFrame(adjusted_args); |
- } |
return true; |
} |
-void Scheduler::SetChildrenNeedBeginFrames(bool children_need_begin_frames) { |
- DCHECK(settings_.forward_begin_frames_to_children); |
- state_machine_.SetChildrenNeedBeginFrames(children_need_begin_frames); |
- DCHECK_EQ(state_machine_.NextAction(), SchedulerStateMachine::ACTION_NONE); |
-} |
- |
-// BeginRetroFrame is called for BeginFrames that we've deferred because |
-// the scheduler was in the middle of processing a previous BeginFrame. |
-void Scheduler::BeginRetroFrame() { |
- TRACE_EVENT0("cc", "Scheduler::BeginRetroFrame"); |
- DCHECK(!settings_.using_synchronous_renderer_compositor); |
- DCHECK(begin_retro_frame_posted_); |
- begin_retro_frame_posted_ = false; |
+void Scheduler::ProcessBeginFrames(bool* clear_posted) { |
+ DCHECK(!begin_retro_frame_args.empty()); |
- // If there aren't any retroactive BeginFrames, then we've lost the |
- // OutputSurface and should abort. |
- if (begin_retro_frame_args_.empty()) |
- return; |
+ if (clear_posted) { |
+ *clear_posted = false; |
+ } |
- // Discard expired BeginRetroFrames |
- // Today, we should always end up with at most one un-expired BeginRetroFrame |
- // because deadlines will not be greater than the next frame time. We don't |
- // DCHECK though because some systems don't always have monotonic timestamps. |
- // TODO(brianderson): In the future, long deadlines could result in us not |
- // draining the queue if we don't catch up. If we consistently can't catch |
- // up, our fallback should be to lower our frame rate. |
+ // Capture now to use for all the deadline calculations |
base::TimeTicks now = Now(); |
- while (!begin_retro_frame_args_.empty()) { |
- const BeginFrameArgs& args = begin_retro_frame_args_.front(); |
- base::TimeTicks expiration_time = args.frame_time + args.interval; |
- if (now <= expiration_time) |
- break; |
- TRACE_EVENT_INSTANT2( |
- "cc", "Scheduler::BeginRetroFrame discarding", TRACE_EVENT_SCOPE_THREAD, |
- "expiration_time - now", (expiration_time - now).InMillisecondsF(), |
- "BeginFrameArgs", begin_retro_frame_args_.front().AsValue()); |
- begin_retro_frame_args_.pop_front(); |
- frame_source_->DidFinishFrame(begin_retro_frame_args_.size()); |
+ // If we have multiple frames to process, discard anything which we can't |
+ // make it's deadline. |
+ while (pending_begin_frame_args_.size() > 1) { |
+ const BeginFrameArgs& args = pending_begin_frame_args_.front(); |
+ |
+ base::TimeTicks deadline = CalculateDeadline(now, args); |
+ if (now >= deadline) { |
+ TRACE_EVENT_INSTANT2( |
+ "cc", "Scheduler::BeginFrame discarding", TRACE_EVENT_SCOPE_THREAD, |
+ "expiration_time - now", (deadline - now).InMillisecondsF(), |
+ "BeginFrameArgs", args.AsValue()); |
+ pending_begin_frame_args_.pop_front(); |
+ frame_source_->DidFinishFrame(pending_begin_frame_args_.size()); |
+ } |
} |
- if (begin_retro_frame_args_.empty()) { |
- TRACE_EVENT_INSTANT0("cc", |
- "Scheduler::BeginRetroFrames all expired", |
- TRACE_EVENT_SCOPE_THREAD); |
- } else { |
- BeginFrameArgs front = begin_retro_frame_args_.front(); |
- begin_retro_frame_args_.pop_front(); |
- BeginImplFrame(front); |
- } |
+ // Process the head of the queue. |
+ BeginFrameArgs front_args = pending_begin_frame_args_.front(); |
+ pending_begin_frame_args_.pop_front(); |
+ front_args.deadline = CalculateDeadline(now, front_args); |
+ BeginImplFrame(now, front_args); |
} |
-// There could be a race between the posted BeginRetroFrame and a new |
-// BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame |
-// will check if there is a pending BeginRetroFrame to ensure we handle |
-// BeginFrames in FIFO order. |
-void Scheduler::PostBeginRetroFrameIfNeeded() { |
- TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), |
- "Scheduler::PostBeginRetroFrameIfNeeded", |
- "state", |
- AsValue()); |
- if (!frame_source_->NeedsBeginFrames()) |
- return; |
- |
- if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_) |
- return; |
- |
- // begin_retro_frame_args_ should always be empty for the |
- // synchronous compositor. |
- DCHECK(!settings_.using_synchronous_renderer_compositor); |
- if (state_machine_.begin_impl_frame_state() != |
- SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE) |
- return; |
- |
- begin_retro_frame_posted_ = true; |
- task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_); |
-} |
- |
-// BeginImplFrame starts a compositor frame that will wait up until a deadline |
-// for a BeginMainFrame+activation to complete before it times out and draws |
-// any asynchronous animation and scroll/pinch updates. |
-void Scheduler::BeginImplFrame(const BeginFrameArgs& args) { |
- bool main_thread_is_in_high_latency_mode = |
- state_machine_.MainThreadIsInHighLatencyMode(); |
- TRACE_EVENT2("cc", |
- "Scheduler::BeginImplFrame", |
- "args", |
- args.AsValue(), |
- "main_thread_is_high_latency", |
- main_thread_is_in_high_latency_mode); |
- TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), |
- "MainThreadLatency", |
- main_thread_is_in_high_latency_mode); |
- DCHECK_EQ(state_machine_.begin_impl_frame_state(), |
- SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); |
- DCHECK(state_machine_.HasInitializedOutputSurface()); |
- |
- advance_commit_state_task_.Cancel(); |
- |
- base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); |
- begin_impl_frame_args_ = args; |
- begin_impl_frame_args_.deadline -= draw_duration_estimate; |
+void Scheduler::BeginImplFrame(base::TimeTicks now, const BeginFrameArgs& args) { |
+ // Clear any pending impl frame deadline |
+ begin_impl_frame_deadline_task_.Cancel(); |
+ begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); |
- if (!state_machine_.impl_latency_takes_priority() && |
- main_thread_is_in_high_latency_mode && |
- CanCommitAndActivateBeforeDeadline()) { |
- state_machine_.SetSkipNextBeginMainFrameToReduceLatency(); |
+ // TODO(mithro): ????? |
+ // Deliver BeginFrames to children. |
+ if (settings_.forward_begin_frames_to_children && |
+ state_machine_.children_need_begin_frames()) { |
+ BeginFrameArgs adjusted_args_for_children(args); |
+ // Adjust a deadline for child schedulers. |
+ // TODO(simonhong): Once we have commitless update, we can get rid of |
+ // BeginMainFrameToCommitDurationEstimate() + |
+ // CommitToActivateDurationEstimate(). |
+ adjusted_args_for_children.deadline -= |
+ (client_->BeginMainFrameToCommitDurationEstimate() + |
+ client_->CommitToActivateDurationEstimate() + |
+ TimeForDrawing()); |
+ client_->SendBeginFramesToChildren(adjusted_args_for_children); |
} |
- client_->WillBeginImplFrame(begin_impl_frame_args_); |
- state_machine_.OnBeginImplFrame(begin_impl_frame_args_); |
- devtools_instrumentation::DidBeginFrame(layer_tree_host_id_); |
- |
- ProcessScheduledActions(); |
- |
- state_machine_.OnBeginImplFrameDeadlinePending(); |
+ // Start the ImplFrame |
+ client_->BeginImplFrame(args); |
- if (settings_.using_synchronous_renderer_compositor) { |
- // The synchronous renderer compositor has to make its GL calls |
- // within this call. |
- // TODO(brianderson): Have the OutputSurface initiate the deadline tasks |
- // so the synchronous renderer compositor can take advantage of splitting |
- // up the BeginImplFrame and deadline as well. |
+ // If we are asked to schedule a deadline in the past, just run the deadline |
+ // right now. |
+ if (now >= args.deadline) { |
OnBeginImplFrameDeadline(); |
- } else { |
- ScheduleBeginImplFrameDeadline( |
- AdjustedBeginImplFrameDeadline(args, draw_duration_estimate)); |
- } |
-} |
- |
-base::TimeTicks Scheduler::AdjustedBeginImplFrameDeadline( |
- const BeginFrameArgs& args, |
- base::TimeDelta draw_duration_estimate) const { |
- // The synchronous compositor does not post a deadline task. |
- DCHECK(!settings_.using_synchronous_renderer_compositor); |
- if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) { |
- // We are ready to draw a new active tree immediately. |
- // We don't use Now() here because it's somewhat expensive to call. |
- return base::TimeTicks(); |
- } else if (state_machine_.needs_redraw()) { |
- // We have an animation or fast input path on the impl thread that wants |
- // to draw, so don't wait too long for a new active tree. |
- return args.deadline - draw_duration_estimate; |
- } else { |
- // The impl thread doesn't have anything it wants to draw and we are just |
- // waiting for a new active tree, so post the deadline for the next |
- // expected BeginImplFrame start. This allows us to draw immediately when |
- // there is a new active tree, instead of waiting for the next |
- // BeginImplFrame. |
- // TODO(brianderson): Handle long deadlines (that are past the next frame's |
- // frame time) properly instead of using this hack. |
- return args.frame_time + args.interval; |
+ return; |
} |
-} |
- |
-void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) { |
- TRACE_EVENT1( |
- "cc", "Scheduler::ScheduleBeginImplFrameDeadline", "deadline", deadline); |
- |
- begin_impl_frame_deadline_task_.Cancel(); |
- begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); |
- |
- base::TimeDelta delta = deadline - Now(); |
- if (delta <= base::TimeDelta()) |
- delta = base::TimeDelta(); |
+ |
+ // Else post a task for the deadline |
task_runner_->PostDelayedTask( |
- FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta); |
+ FROM_HERE, begin_impl_frame_deadline_task_.callback(), now - deadline); |
} |
void Scheduler::OnBeginImplFrameDeadline() { |
TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline"); |
begin_impl_frame_deadline_task_.Cancel(); |
+ last_begin_impl_frame_args_ = current_begin_impl_frame_args_; |
+ |
// We split the deadline actions up into two phases so the state machine |
- // has a chance to trigger actions that should occur durring and after |
- // the deadline separately. For example: |
+ // has a chance to trigger actions that should occur during and after the |
+ // deadline separately. For example: |
// * Sending the BeginMainFrame will not occur after the deadline in |
// order to wait for more user-input before starting the next commit. |
// * Creating a new OuputSurface will not occur during the deadline in |
@@ -632,6 +511,120 @@ void Scheduler::OnBeginImplFrameDeadline() { |
client_->DidBeginImplFrameDeadline(); |
} |
+void Scheduler::DidActivateSyncTree() { |
+ // Main frame is committed and activated |
+ last_main_frame_args_ = current_main_frame_args_; |
+ current_main_frame_args_ = BeginFrameArgs(); |
+} |
+ |
+BeginFrameArgs Scheduler::GetBeginMainFrameArgs() { |
+ // Did the previous main frame meet the deadline? |
+ bool last_main_frame_meet_deadline = (last_main_frame_args_.frame_time == last_impl_frame_args_.frame_time); |
+ |
+ BeginFrameArgs args(current_impl_frame_args_); |
+ // We aren't inside an active impl frame deadline, so we use the values of |
+ // the last impl frame. |
+ // TODO(mithro): This includes deadline adjustment for draw time which could |
+ // instead be given to the main frame. |
+ if (!args.is_valid()) { |
+ args = last_impl_frame_args_; |
+ } |
+ |
+ // Do we think the main frame can make the deadline? |
+ base::TimeDelta main_thread_time = |
+ client_->BeginMainFrameToCommitDurationEstimate() + |
+ client_->CommitToActivateDurationEstimate(); |
+ if (now + main_thread_time <= args.deadline) { |
+ // If we think the BeginMainFrame will make the deadline, we should |
+ // definitely go ahead. |
+ return args; |
+ } |
+ |
+ base::TimeDelta will_missed_deadline_by = now + main_thread_time - args.deadline; |
+ |
+/* |
+ // If we think the BeginMainFrame will only miss by a little and we made the |
+ // last deadline, we are going to give it a go and see if we actually miss. |
+ // This exists because our estimates are rough and there is jitter in the |
+ // system. |
+ bool close_deadline_miss = (will_missed_deadline_by / base::TimeDelta::FromMilliseconds(1)) == 0; |
+ if (last_main_frame_meet_deadline && close_deadline_miss) { |
+ return args; |
+ } |
+*/ |
+ |
+ // Otherwise, we don't think the BeginMainFrame will make the deadline and |
+ // have already missed the last frame. What we do depends on if we think |
+ // sending a BeginMainFrame now will effect the next frame's ability to meet |
+ // the deadline. |
+ |
+ // Work out what percentage of an normal interval the main thread rendering |
+ // will take. |
+ base::TimeDelta time_for_rendering = args.interval - (EstimatedParentDrawTime() + client_->DrawDurationEstimate()); |
+ double main_percentage_of_rendering_time = main_thread_time.InMillisecondsF() / time_for_rendering.InMillisecondsF(); |
+ |
+ if (main_percentage_of_rendering_time < 0.5) { |
+ // As the main thread can render twice a frame, starting rendering is |
+ // unlikely to cause us to miss the next frame. Let's try and catch the |
+ // main thread up to the impl thread to help with latency. |
+ // We keep the expired deadline so main thread knows it not to run any |
+ // unimportant tasks. It will have time after we catch back up. |
+ return args; |
+ } |
+ |
+ if (main_percentage_of_rendering_time > 1.0) { |
+ // Values greater than 1.0 mean the main thread will never make a normal |
+ // deadline. |
+ |
+ // If we could meet 50% of the interval, then we assume that we will do |
+ // that and start rendering ASAP. |
+ if (main_percentage_of_rendering_time < 2.0) { |
+ // Adjust the deadline to the next deadline we think the main thread will |
+ // probably make. |
+ while (args.deadline + time_for_rendering >= now) { |
+ args.deadline += args.interval; |
+ } |
+ return args; |
+ } |
+ |
+ // If the main thread isn't even going to make 50% frame rate, just target |
+ // throughput and render as fast as we can. We clear the deadline to inform |
+ // the main thread that we are targeting throughput and want to minimize |
+ // context switches. |
+ args.deadline = base::TimeTicks(); |
+ return args; |
+ } |
+ |
+ // If main_percentage_of_rendering_time is between 0.5 and 1.0, then if we |
+ // start rendering too late it will break the next frame too. However, we |
+ // have to be careful we don't drop *every* main frame on the floor. |
+ |
+ // If we are missing the deadline by the "slack" in the next frame, then we |
+ // should go ahead. |
+ base::TimeDelta slack_in_next_frame = time_for_rendering - main_thread_time; |
+ if (will_miss_deadline_by < slack_in_next_frame) { |
+ // We don't adjust the deadline because we want this main frame to return |
+ // as early as possible to give the next main frame as much chance as |
+ // possible. |
+ return args; |
+ } |
+ |
+ if (last_main_frame_meet_deadline == DROPPED) { |
+ // Drop this main frame to allow the next main frame to start as soon as |
+ // the BeginFrame message occurs. |
+ return args; |
+ } else { |
+ return BeginFrameArgs(); |
+ } |
+} |
+ |
+void Scheduler::SetChildrenNeedBeginFrames(bool children_need_begin_frames) { |
+ DCHECK(settings_.forward_begin_frames_to_children); |
+ state_machine_.SetChildrenNeedBeginFrames(children_need_begin_frames); |
+ DCHECK_EQ(state_machine_.NextAction(), SchedulerStateMachine::ACTION_NONE); |
+} |
+ |
+ |
void Scheduler::PollForAnticipatedDrawTriggers() { |
TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers"); |
poll_for_draw_triggers_task_.Cancel(); |
@@ -679,6 +672,14 @@ void Scheduler::ProcessScheduledActions() { |
client_->ScheduledActionAnimate(); |
break; |
case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME: |
+ |
+ // FIXME:!!!!!!! |
+ BeginFrameArgs args = GetBeginMainFrameArgs(); |
+ if (!args.IsValid()) |
+ continue; |
+ current_main_frame_args_ = args; |
+ // FIXME:!!!!!!! |
+ |
client_->ScheduledActionSendBeginMainFrame(); |
break; |
case SchedulerStateMachine::ACTION_COMMIT: |
@@ -707,11 +708,9 @@ void Scheduler::ProcessScheduledActions() { |
} while (action != SchedulerStateMachine::ACTION_NONE); |
SetupNextBeginFrameIfNeeded(); |
- client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); |
- |
if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) { |
DCHECK(!settings_.using_synchronous_renderer_compositor); |
- ScheduleBeginImplFrameDeadline(base::TimeTicks()); |
+ OnBeginImplFrameDeadline(); |
} |
} |
@@ -750,8 +749,8 @@ void Scheduler::AsValueInto(base::debug::TracedValue* state) const { |
estimated_parent_draw_time_.InMillisecondsF()); |
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_frame_process_posted_", begin_frame_process_posted_); |
+ state->SetInteger("pending_begin_frame_args_", pending_begin_frame_args_.size()); |
state->SetBoolean("begin_impl_frame_deadline_task_", |
!begin_impl_frame_deadline_task_.IsCancelled()); |
state->SetBoolean("poll_for_draw_triggers_task_", |
@@ -776,25 +775,6 @@ void Scheduler::AsValueInto(base::debug::TracedValue* state) const { |
state->EndDictionary(); |
} |
-bool Scheduler::CanCommitAndActivateBeforeDeadline() const { |
- // Check if the main thread computation and commit can be finished before the |
- // impl thread's deadline. |
- base::TimeTicks estimated_draw_time = |
- begin_impl_frame_args_.frame_time + |
- client_->BeginMainFrameToCommitDurationEstimate() + |
- client_->CommitToActivateDurationEstimate(); |
- |
- TRACE_EVENT2( |
- TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), |
- "CanCommitAndActivateBeforeDeadline", |
- "time_left_after_drawing_ms", |
- (begin_impl_frame_args_.deadline - estimated_draw_time).InMillisecondsF(), |
- "state", |
- AsValue()); |
- |
- return estimated_draw_time < begin_impl_frame_args_.deadline; |
-} |
- |
bool Scheduler::IsBeginMainFrameSentOrStarted() const { |
return (state_machine_.commit_state() == |
SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || |