Enable gaia services for enterprise autotests.
[chromium-blink-merge.git] / cc / scheduler / scheduler.cc
blobe98f96689e16f247bf23482997264bb49bb8db9c
1 // Copyright 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/scheduler/scheduler.h"
7 #include <algorithm>
8 #include "base/auto_reset.h"
9 #include "base/debug/trace_event.h"
10 #include "base/debug/trace_event_argument.h"
11 #include "base/logging.h"
12 #include "base/single_thread_task_runner.h"
13 #include "cc/debug/devtools_instrumentation.h"
14 #include "cc/debug/traced_value.h"
15 #include "cc/scheduler/delay_based_time_source.h"
16 #include "ui/gfx/frame_time.h"
18 namespace cc {
20 Scheduler::SyntheticBeginFrameSource::SyntheticBeginFrameSource(
21 Scheduler* scheduler,
22 scoped_refptr<DelayBasedTimeSource> time_source)
23 : scheduler_(scheduler), time_source_(time_source) {
24 time_source_->SetClient(this);
27 Scheduler::SyntheticBeginFrameSource::~SyntheticBeginFrameSource() {
30 void Scheduler::SyntheticBeginFrameSource::CommitVSyncParameters(
31 base::TimeTicks timebase,
32 base::TimeDelta interval) {
33 time_source_->SetTimebaseAndInterval(timebase, interval);
36 void Scheduler::SyntheticBeginFrameSource::SetNeedsBeginFrame(
37 bool needs_begin_frame,
38 std::deque<BeginFrameArgs>* begin_retro_frame_args) {
39 DCHECK(begin_retro_frame_args);
40 base::TimeTicks missed_tick_time =
41 time_source_->SetActive(needs_begin_frame);
42 if (!missed_tick_time.is_null()) {
43 begin_retro_frame_args->push_back(
44 CreateSyntheticBeginFrameArgs(missed_tick_time));
48 bool Scheduler::SyntheticBeginFrameSource::IsActive() const {
49 return time_source_->Active();
52 void Scheduler::SyntheticBeginFrameSource::OnTimerTick() {
53 BeginFrameArgs begin_frame_args(
54 CreateSyntheticBeginFrameArgs(time_source_->LastTickTime()));
55 scheduler_->BeginFrame(begin_frame_args);
58 void Scheduler::SyntheticBeginFrameSource::AsValueInto(
59 base::debug::TracedValue* state) const {
60 time_source_->AsValueInto(state);
63 BeginFrameArgs
64 Scheduler::SyntheticBeginFrameSource::CreateSyntheticBeginFrameArgs(
65 base::TimeTicks frame_time) {
66 base::TimeTicks deadline = time_source_->NextTickTime();
67 return BeginFrameArgs::Create(
68 frame_time, deadline, scheduler_->VSyncInterval());
71 Scheduler::Scheduler(
72 SchedulerClient* client,
73 const SchedulerSettings& scheduler_settings,
74 int layer_tree_host_id,
75 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
76 : settings_(scheduler_settings),
77 client_(client),
78 layer_tree_host_id_(layer_tree_host_id),
79 task_runner_(task_runner),
80 vsync_interval_(BeginFrameArgs::DefaultInterval()),
81 last_set_needs_begin_frame_(false),
82 begin_unthrottled_frame_posted_(false),
83 begin_retro_frame_posted_(false),
84 state_machine_(scheduler_settings),
85 inside_process_scheduled_actions_(false),
86 inside_action_(SchedulerStateMachine::ACTION_NONE),
87 weak_factory_(this) {
88 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
89 "Scheduler::Scheduler",
90 "settings",
91 settings_.AsValue());
92 DCHECK(client_);
93 DCHECK(!state_machine_.BeginFrameNeeded());
94 if (settings_.main_frame_before_activation_enabled) {
95 DCHECK(settings_.main_frame_before_draw_enabled);
98 begin_retro_frame_closure_ =
99 base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr());
100 begin_unthrottled_frame_closure_ =
101 base::Bind(&Scheduler::BeginUnthrottledFrame, weak_factory_.GetWeakPtr());
102 begin_impl_frame_deadline_closure_ = base::Bind(
103 &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr());
104 poll_for_draw_triggers_closure_ = base::Bind(
105 &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr());
106 advance_commit_state_closure_ = base::Bind(
107 &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr());
109 if (!settings_.begin_frame_scheduling_enabled) {
110 SetupSyntheticBeginFrames();
114 Scheduler::~Scheduler() {
115 if (synthetic_begin_frame_source_) {
116 synthetic_begin_frame_source_->SetNeedsBeginFrame(false,
117 &begin_retro_frame_args_);
121 void Scheduler::SetupSyntheticBeginFrames() {
122 scoped_refptr<DelayBasedTimeSource> time_source;
123 if (gfx::FrameTime::TimestampsAreHighRes()) {
124 time_source = DelayBasedTimeSourceHighRes::Create(VSyncInterval(),
125 task_runner_.get());
126 } else {
127 time_source =
128 DelayBasedTimeSource::Create(VSyncInterval(), task_runner_.get());
130 DCHECK(!synthetic_begin_frame_source_);
131 synthetic_begin_frame_source_.reset(
132 new SyntheticBeginFrameSource(this, time_source));
135 base::TimeTicks Scheduler::Now() const {
136 return gfx::FrameTime::Now();
139 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase,
140 base::TimeDelta interval) {
141 // TODO(brianderson): We should not be receiving 0 intervals.
142 if (interval == base::TimeDelta())
143 interval = BeginFrameArgs::DefaultInterval();
144 vsync_interval_ = interval;
145 if (!settings_.begin_frame_scheduling_enabled)
146 synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval);
149 void Scheduler::SetEstimatedParentDrawTime(base::TimeDelta draw_time) {
150 DCHECK_GE(draw_time.ToInternalValue(), 0);
151 estimated_parent_draw_time_ = draw_time;
154 void Scheduler::SetCanStart() {
155 state_machine_.SetCanStart();
156 ProcessScheduledActions();
159 void Scheduler::SetVisible(bool visible) {
160 state_machine_.SetVisible(visible);
161 ProcessScheduledActions();
164 void Scheduler::SetCanDraw(bool can_draw) {
165 state_machine_.SetCanDraw(can_draw);
166 ProcessScheduledActions();
169 void Scheduler::NotifyReadyToActivate() {
170 state_machine_.NotifyReadyToActivate();
171 ProcessScheduledActions();
174 void Scheduler::SetNeedsCommit() {
175 state_machine_.SetNeedsCommit();
176 ProcessScheduledActions();
179 void Scheduler::SetNeedsRedraw() {
180 state_machine_.SetNeedsRedraw();
181 ProcessScheduledActions();
184 void Scheduler::SetNeedsAnimate() {
185 state_machine_.SetNeedsAnimate();
186 ProcessScheduledActions();
189 void Scheduler::SetNeedsManageTiles() {
190 DCHECK(!IsInsideAction(SchedulerStateMachine::ACTION_MANAGE_TILES));
191 state_machine_.SetNeedsManageTiles();
192 ProcessScheduledActions();
195 void Scheduler::SetMaxSwapsPending(int max) {
196 state_machine_.SetMaxSwapsPending(max);
199 void Scheduler::DidSwapBuffers() {
200 state_machine_.DidSwapBuffers();
202 // There is no need to call ProcessScheduledActions here because
203 // swapping should not trigger any new actions.
204 if (!inside_process_scheduled_actions_) {
205 DCHECK_EQ(state_machine_.NextAction(), SchedulerStateMachine::ACTION_NONE);
209 void Scheduler::SetSwapUsedIncompleteTile(bool used_incomplete_tile) {
210 state_machine_.SetSwapUsedIncompleteTile(used_incomplete_tile);
211 ProcessScheduledActions();
214 void Scheduler::DidSwapBuffersComplete() {
215 state_machine_.DidSwapBuffersComplete();
216 ProcessScheduledActions();
219 void Scheduler::SetImplLatencyTakesPriority(bool impl_latency_takes_priority) {
220 state_machine_.SetImplLatencyTakesPriority(impl_latency_takes_priority);
221 ProcessScheduledActions();
224 void Scheduler::NotifyReadyToCommit() {
225 TRACE_EVENT0("cc", "Scheduler::NotifyReadyToCommit");
226 state_machine_.NotifyReadyToCommit();
227 ProcessScheduledActions();
230 void Scheduler::BeginMainFrameAborted(bool did_handle) {
231 TRACE_EVENT0("cc", "Scheduler::BeginMainFrameAborted");
232 state_machine_.BeginMainFrameAborted(did_handle);
233 ProcessScheduledActions();
236 void Scheduler::DidManageTiles() {
237 state_machine_.DidManageTiles();
240 void Scheduler::DidLoseOutputSurface() {
241 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface");
242 state_machine_.DidLoseOutputSurface();
243 last_set_needs_begin_frame_ = false;
244 if (!settings_.begin_frame_scheduling_enabled) {
245 synthetic_begin_frame_source_->SetNeedsBeginFrame(false,
246 &begin_retro_frame_args_);
248 begin_retro_frame_args_.clear();
249 ProcessScheduledActions();
252 void Scheduler::DidCreateAndInitializeOutputSurface() {
253 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface");
254 DCHECK(!last_set_needs_begin_frame_);
255 DCHECK(begin_impl_frame_deadline_task_.IsCancelled());
256 state_machine_.DidCreateAndInitializeOutputSurface();
257 ProcessScheduledActions();
260 void Scheduler::NotifyBeginMainFrameStarted() {
261 TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted");
262 state_machine_.NotifyBeginMainFrameStarted();
265 base::TimeTicks Scheduler::AnticipatedDrawTime() const {
266 if (!last_set_needs_begin_frame_ ||
267 begin_impl_frame_args_.interval <= base::TimeDelta())
268 return base::TimeTicks();
270 base::TimeTicks now = Now();
271 base::TimeTicks timebase = std::max(begin_impl_frame_args_.frame_time,
272 begin_impl_frame_args_.deadline);
273 int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval);
274 return timebase + (begin_impl_frame_args_.interval * intervals);
277 base::TimeTicks Scheduler::LastBeginImplFrameTime() {
278 return begin_impl_frame_args_.frame_time;
281 void Scheduler::SetupNextBeginFrameIfNeeded() {
282 if (!task_runner_.get())
283 return;
285 bool needs_begin_frame = state_machine_.BeginFrameNeeded();
287 if (settings_.throttle_frame_production) {
288 SetupNextBeginFrameWhenVSyncThrottlingEnabled(needs_begin_frame);
289 } else {
290 SetupNextBeginFrameWhenVSyncThrottlingDisabled(needs_begin_frame);
292 SetupPollingMechanisms(needs_begin_frame);
295 // When we are throttling frame production, we request BeginFrames
296 // from the OutputSurface.
297 void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingEnabled(
298 bool needs_begin_frame) {
299 bool at_end_of_deadline =
300 state_machine_.begin_impl_frame_state() ==
301 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE;
303 bool should_call_set_needs_begin_frame =
304 // Always request the BeginFrame immediately if it wasn't needed before.
305 (needs_begin_frame && !last_set_needs_begin_frame_) ||
306 // Only stop requesting BeginFrames after a deadline.
307 (!needs_begin_frame && last_set_needs_begin_frame_ && at_end_of_deadline);
309 if (should_call_set_needs_begin_frame) {
310 if (settings_.begin_frame_scheduling_enabled) {
311 client_->SetNeedsBeginFrame(needs_begin_frame);
312 } else {
313 synthetic_begin_frame_source_->SetNeedsBeginFrame(
314 needs_begin_frame, &begin_retro_frame_args_);
316 last_set_needs_begin_frame_ = needs_begin_frame;
319 PostBeginRetroFrameIfNeeded();
322 // When we aren't throttling frame production, we initiate a BeginFrame
323 // as soon as one is needed.
324 void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingDisabled(
325 bool needs_begin_frame) {
326 last_set_needs_begin_frame_ = needs_begin_frame;
328 if (!needs_begin_frame || begin_unthrottled_frame_posted_)
329 return;
331 if (state_machine_.begin_impl_frame_state() !=
332 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE &&
333 state_machine_.begin_impl_frame_state() !=
334 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) {
335 return;
338 begin_unthrottled_frame_posted_ = true;
339 task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_);
342 // BeginUnthrottledFrame is used when we aren't throttling frame production.
343 // This will usually be because VSync is disabled.
344 void Scheduler::BeginUnthrottledFrame() {
345 DCHECK(!settings_.throttle_frame_production);
346 DCHECK(begin_retro_frame_args_.empty());
348 base::TimeTicks now = Now();
349 base::TimeTicks deadline = now + vsync_interval_;
351 BeginFrameArgs begin_frame_args =
352 BeginFrameArgs::Create(now, deadline, vsync_interval_);
353 BeginImplFrame(begin_frame_args);
355 begin_unthrottled_frame_posted_ = false;
358 // We may need to poll when we can't rely on BeginFrame to advance certain
359 // state or to avoid deadlock.
360 void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) {
361 bool needs_advance_commit_state_timer = false;
362 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but
363 // aren't expecting any more BeginFrames. This should only be needed by
364 // the synchronous compositor when BeginFrameNeeded is false.
365 if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) {
366 DCHECK(!state_machine_.SupportsProactiveBeginFrame());
367 DCHECK(!needs_begin_frame);
368 if (poll_for_draw_triggers_task_.IsCancelled()) {
369 poll_for_draw_triggers_task_.Reset(poll_for_draw_triggers_closure_);
370 base::TimeDelta delay = begin_impl_frame_args_.IsValid()
371 ? begin_impl_frame_args_.interval
372 : BeginFrameArgs::DefaultInterval();
373 task_runner_->PostDelayedTask(
374 FROM_HERE, poll_for_draw_triggers_task_.callback(), delay);
376 } else {
377 poll_for_draw_triggers_task_.Cancel();
379 // At this point we'd prefer to advance through the commit flow by
380 // drawing a frame, however it's possible that the frame rate controller
381 // will not give us a BeginFrame until the commit completes. See
382 // crbug.com/317430 for an example of a swap ack being held on commit. Thus
383 // we set a repeating timer to poll on ProcessScheduledActions until we
384 // successfully reach BeginFrame. Synchronous compositor does not use
385 // frame rate controller or have the circular wait in the bug.
386 if (IsBeginMainFrameSentOrStarted() &&
387 !settings_.using_synchronous_renderer_compositor) {
388 needs_advance_commit_state_timer = true;
392 if (needs_advance_commit_state_timer) {
393 if (advance_commit_state_task_.IsCancelled() &&
394 begin_impl_frame_args_.IsValid()) {
395 // Since we'd rather get a BeginImplFrame by the normal mechanism, we
396 // set the interval to twice the interval from the previous frame.
397 advance_commit_state_task_.Reset(advance_commit_state_closure_);
398 task_runner_->PostDelayedTask(FROM_HERE,
399 advance_commit_state_task_.callback(),
400 begin_impl_frame_args_.interval * 2);
402 } else {
403 advance_commit_state_task_.Cancel();
407 // BeginFrame is the mechanism that tells us that now is a good time to start
408 // making a frame. Usually this means that user input for the frame is complete.
409 // If the scheduler is busy, we queue the BeginFrame to be handled later as
410 // a BeginRetroFrame.
411 void Scheduler::BeginFrame(const BeginFrameArgs& args) {
412 TRACE_EVENT1("cc", "Scheduler::BeginFrame", "args", args.AsValue());
413 DCHECK(settings_.throttle_frame_production);
415 BeginFrameArgs adjusted_args(args);
416 adjusted_args.deadline -= EstimatedParentDrawTime();
418 bool should_defer_begin_frame;
419 if (settings_.using_synchronous_renderer_compositor) {
420 should_defer_begin_frame = false;
421 } else {
422 should_defer_begin_frame =
423 !begin_retro_frame_args_.empty() || begin_retro_frame_posted_ ||
424 !last_set_needs_begin_frame_ ||
425 (state_machine_.begin_impl_frame_state() !=
426 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
429 if (should_defer_begin_frame) {
430 begin_retro_frame_args_.push_back(adjusted_args);
431 TRACE_EVENT_INSTANT0(
432 "cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD);
433 return;
436 BeginImplFrame(adjusted_args);
439 // BeginRetroFrame is called for BeginFrames that we've deferred because
440 // the scheduler was in the middle of processing a previous BeginFrame.
441 void Scheduler::BeginRetroFrame() {
442 TRACE_EVENT0("cc", "Scheduler::BeginRetroFrame");
443 DCHECK(!settings_.using_synchronous_renderer_compositor);
444 DCHECK(begin_retro_frame_posted_);
445 begin_retro_frame_posted_ = false;
447 // If there aren't any retroactive BeginFrames, then we've lost the
448 // OutputSurface and should abort.
449 if (begin_retro_frame_args_.empty())
450 return;
452 // Discard expired BeginRetroFrames
453 // Today, we should always end up with at most one un-expired BeginRetroFrame
454 // because deadlines will not be greater than the next frame time. We don't
455 // DCHECK though because some systems don't always have monotonic timestamps.
456 // TODO(brianderson): In the future, long deadlines could result in us not
457 // draining the queue if we don't catch up. If we consistently can't catch
458 // up, our fallback should be to lower our frame rate.
459 base::TimeTicks now = Now();
460 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate();
461 while (!begin_retro_frame_args_.empty()) {
462 base::TimeTicks adjusted_deadline = AdjustedBeginImplFrameDeadline(
463 begin_retro_frame_args_.front(), draw_duration_estimate);
464 if (now <= adjusted_deadline)
465 break;
467 TRACE_EVENT_INSTANT2("cc",
468 "Scheduler::BeginRetroFrame discarding",
469 TRACE_EVENT_SCOPE_THREAD,
470 "deadline - now",
471 (adjusted_deadline - now).InMicroseconds(),
472 "BeginFrameArgs",
473 begin_retro_frame_args_.front().AsValue());
474 begin_retro_frame_args_.pop_front();
477 if (begin_retro_frame_args_.empty()) {
478 DCHECK(settings_.throttle_frame_production);
479 TRACE_EVENT_INSTANT0("cc",
480 "Scheduler::BeginRetroFrames all expired",
481 TRACE_EVENT_SCOPE_THREAD);
482 } else {
483 BeginImplFrame(begin_retro_frame_args_.front());
484 begin_retro_frame_args_.pop_front();
488 // There could be a race between the posted BeginRetroFrame and a new
489 // BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame
490 // will check if there is a pending BeginRetroFrame to ensure we handle
491 // BeginFrames in FIFO order.
492 void Scheduler::PostBeginRetroFrameIfNeeded() {
493 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
494 "Scheduler::PostBeginRetroFrameIfNeeded",
495 "state",
496 AsValue());
497 if (!last_set_needs_begin_frame_)
498 return;
500 if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_)
501 return;
503 // begin_retro_frame_args_ should always be empty for the
504 // synchronous compositor.
505 DCHECK(!settings_.using_synchronous_renderer_compositor);
507 if (state_machine_.begin_impl_frame_state() !=
508 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE)
509 return;
511 begin_retro_frame_posted_ = true;
512 task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_);
515 // BeginImplFrame starts a compositor frame that will wait up until a deadline
516 // for a BeginMainFrame+activation to complete before it times out and draws
517 // any asynchronous animation and scroll/pinch updates.
518 void Scheduler::BeginImplFrame(const BeginFrameArgs& args) {
519 TRACE_EVENT1("cc", "Scheduler::BeginImplFrame", "args", args.AsValue());
520 DCHECK_EQ(state_machine_.begin_impl_frame_state(),
521 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
522 DCHECK(state_machine_.HasInitializedOutputSurface());
524 advance_commit_state_task_.Cancel();
526 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate();
527 begin_impl_frame_args_ = args;
528 begin_impl_frame_args_.deadline -= draw_duration_estimate;
530 if (!state_machine_.impl_latency_takes_priority() &&
531 state_machine_.MainThreadIsInHighLatencyMode() &&
532 CanCommitAndActivateBeforeDeadline()) {
533 state_machine_.SetSkipNextBeginMainFrameToReduceLatency();
536 client_->WillBeginImplFrame(begin_impl_frame_args_);
537 state_machine_.OnBeginImplFrame(begin_impl_frame_args_);
538 devtools_instrumentation::DidBeginFrame(layer_tree_host_id_);
540 ProcessScheduledActions();
542 state_machine_.OnBeginImplFrameDeadlinePending();
543 ScheduleBeginImplFrameDeadline(
544 AdjustedBeginImplFrameDeadline(args, draw_duration_estimate));
547 base::TimeTicks Scheduler::AdjustedBeginImplFrameDeadline(
548 const BeginFrameArgs& args,
549 base::TimeDelta draw_duration_estimate) const {
550 if (settings_.using_synchronous_renderer_compositor) {
551 // The synchronous compositor needs to draw right away.
552 return base::TimeTicks();
553 } else if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
554 // We are ready to draw a new active tree immediately.
555 return base::TimeTicks();
556 } else if (state_machine_.needs_redraw()) {
557 // We have an animation or fast input path on the impl thread that wants
558 // to draw, so don't wait too long for a new active tree.
559 return args.deadline - draw_duration_estimate;
560 } else {
561 // The impl thread doesn't have anything it wants to draw and we are just
562 // waiting for a new active tree, so post the deadline for the next
563 // expected BeginImplFrame start. This allows us to draw immediately when
564 // there is a new active tree, instead of waiting for the next
565 // BeginImplFrame.
566 // TODO(brianderson): Handle long deadlines (that are past the next frame's
567 // frame time) properly instead of using this hack.
568 return args.frame_time + args.interval;
572 void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) {
573 TRACE_EVENT1(
574 "cc", "Scheduler::ScheduleBeginImplFrameDeadline", "deadline", deadline);
575 if (settings_.using_synchronous_renderer_compositor) {
576 // The synchronous renderer compositor has to make its GL calls
577 // within this call.
578 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks
579 // so the sychronous renderer compositor can take advantage of splitting
580 // up the BeginImplFrame and deadline as well.
581 OnBeginImplFrameDeadline();
582 return;
584 begin_impl_frame_deadline_task_.Cancel();
585 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_);
587 base::TimeDelta delta = deadline - Now();
588 if (delta <= base::TimeDelta())
589 delta = base::TimeDelta();
590 task_runner_->PostDelayedTask(
591 FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta);
594 void Scheduler::OnBeginImplFrameDeadline() {
595 TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline");
596 begin_impl_frame_deadline_task_.Cancel();
598 // We split the deadline actions up into two phases so the state machine
599 // has a chance to trigger actions that should occur durring and after
600 // the deadline separately. For example:
601 // * Sending the BeginMainFrame will not occur after the deadline in
602 // order to wait for more user-input before starting the next commit.
603 // * Creating a new OuputSurface will not occur during the deadline in
604 // order to allow the state machine to "settle" first.
605 state_machine_.OnBeginImplFrameDeadline();
606 ProcessScheduledActions();
607 state_machine_.OnBeginImplFrameIdle();
608 ProcessScheduledActions();
610 client_->DidBeginImplFrameDeadline();
613 void Scheduler::PollForAnticipatedDrawTriggers() {
614 TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers");
615 poll_for_draw_triggers_task_.Cancel();
616 state_machine_.DidEnterPollForAnticipatedDrawTriggers();
617 ProcessScheduledActions();
618 state_machine_.DidLeavePollForAnticipatedDrawTriggers();
621 void Scheduler::PollToAdvanceCommitState() {
622 TRACE_EVENT0("cc", "Scheduler::PollToAdvanceCommitState");
623 advance_commit_state_task_.Cancel();
624 ProcessScheduledActions();
627 void Scheduler::DrawAndSwapIfPossible() {
628 DrawResult result = client_->ScheduledActionDrawAndSwapIfPossible();
629 state_machine_.DidDrawIfPossibleCompleted(result);
632 void Scheduler::ProcessScheduledActions() {
633 // We do not allow ProcessScheduledActions to be recursive.
634 // The top-level call will iteratively execute the next action for us anyway.
635 if (inside_process_scheduled_actions_)
636 return;
638 base::AutoReset<bool> mark_inside(&inside_process_scheduled_actions_, true);
640 SchedulerStateMachine::Action action;
641 do {
642 action = state_machine_.NextAction();
643 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
644 "SchedulerStateMachine",
645 "state",
646 AsValue());
647 VLOG(2) << "Scheduler::ProcessScheduledActions: "
648 << SchedulerStateMachine::ActionToString(action) << " "
649 << state_machine_.GetStatesForDebugging();
650 state_machine_.UpdateState(action);
651 base::AutoReset<SchedulerStateMachine::Action>
652 mark_inside_action(&inside_action_, action);
653 switch (action) {
654 case SchedulerStateMachine::ACTION_NONE:
655 break;
656 case SchedulerStateMachine::ACTION_ANIMATE:
657 client_->ScheduledActionAnimate();
658 break;
659 case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME:
660 client_->ScheduledActionSendBeginMainFrame();
661 break;
662 case SchedulerStateMachine::ACTION_COMMIT:
663 client_->ScheduledActionCommit();
664 break;
665 case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES:
666 client_->ScheduledActionUpdateVisibleTiles();
667 break;
668 case SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE:
669 client_->ScheduledActionActivateSyncTree();
670 break;
671 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
672 DrawAndSwapIfPossible();
673 break;
674 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED:
675 client_->ScheduledActionDrawAndSwapForced();
676 break;
677 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT:
678 // No action is actually performed, but this allows the state machine to
679 // advance out of its waiting to draw state without actually drawing.
680 break;
681 case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
682 client_->ScheduledActionBeginOutputSurfaceCreation();
683 break;
684 case SchedulerStateMachine::ACTION_MANAGE_TILES:
685 client_->ScheduledActionManageTiles();
686 break;
688 } while (action != SchedulerStateMachine::ACTION_NONE);
690 SetupNextBeginFrameIfNeeded();
691 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime());
693 if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
694 DCHECK(!settings_.using_synchronous_renderer_compositor);
695 ScheduleBeginImplFrameDeadline(base::TimeTicks());
699 bool Scheduler::WillDrawIfNeeded() const {
700 return !state_machine_.PendingDrawsShouldBeAborted();
703 scoped_refptr<base::debug::ConvertableToTraceFormat> Scheduler::AsValue()
704 const {
705 scoped_refptr<base::debug::TracedValue> state =
706 new base::debug::TracedValue();
707 AsValueInto(state.get());
708 return state;
711 void Scheduler::AsValueInto(base::debug::TracedValue* state) const {
712 state->BeginDictionary("state_machine");
713 state_machine_.AsValueInto(state, Now());
714 state->EndDictionary();
715 if (synthetic_begin_frame_source_) {
716 state->BeginDictionary("synthetic_begin_frame_source_");
717 synthetic_begin_frame_source_->AsValueInto(state);
718 state->EndDictionary();
721 state->BeginDictionary("scheduler_state");
722 state->SetDouble("time_until_anticipated_draw_time_ms",
723 (AnticipatedDrawTime() - Now()).InMillisecondsF());
724 state->SetDouble("vsync_interval_ms", vsync_interval_.InMillisecondsF());
725 state->SetDouble("estimated_parent_draw_time_ms",
726 estimated_parent_draw_time_.InMillisecondsF());
727 state->SetBoolean("last_set_needs_begin_frame_", last_set_needs_begin_frame_);
728 state->SetBoolean("begin_unthrottled_frame_posted_",
729 begin_unthrottled_frame_posted_);
730 state->SetBoolean("begin_retro_frame_posted_", begin_retro_frame_posted_);
731 state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size());
732 state->SetBoolean("begin_impl_frame_deadline_task_",
733 !begin_impl_frame_deadline_task_.IsCancelled());
734 state->SetBoolean("poll_for_draw_triggers_task_",
735 !poll_for_draw_triggers_task_.IsCancelled());
736 state->SetBoolean("advance_commit_state_task_",
737 !advance_commit_state_task_.IsCancelled());
738 state->BeginDictionary("begin_impl_frame_args");
739 begin_impl_frame_args_.AsValueInto(state);
740 state->EndDictionary();
742 state->EndDictionary();
744 state->BeginDictionary("client_state");
745 state->SetDouble("draw_duration_estimate_ms",
746 client_->DrawDurationEstimate().InMillisecondsF());
747 state->SetDouble(
748 "begin_main_frame_to_commit_duration_estimate_ms",
749 client_->BeginMainFrameToCommitDurationEstimate().InMillisecondsF());
750 state->SetDouble(
751 "commit_to_activate_duration_estimate_ms",
752 client_->CommitToActivateDurationEstimate().InMillisecondsF());
753 state->EndDictionary();
756 bool Scheduler::CanCommitAndActivateBeforeDeadline() const {
757 // Check if the main thread computation and commit can be finished before the
758 // impl thread's deadline.
759 base::TimeTicks estimated_draw_time =
760 begin_impl_frame_args_.frame_time +
761 client_->BeginMainFrameToCommitDurationEstimate() +
762 client_->CommitToActivateDurationEstimate();
764 TRACE_EVENT2(
765 TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
766 "CanCommitAndActivateBeforeDeadline",
767 "time_left_after_drawing_ms",
768 (begin_impl_frame_args_.deadline - estimated_draw_time).InMillisecondsF(),
769 "state",
770 AsValue());
772 return estimated_draw_time < begin_impl_frame_args_.deadline;
775 bool Scheduler::IsBeginMainFrameSentOrStarted() const {
776 return (state_machine_.commit_state() ==
777 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT ||
778 state_machine_.commit_state() ==
779 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED);
782 } // namespace cc