| 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 ||
|
|
|