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"
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"
20 Scheduler::SyntheticBeginFrameSource::SyntheticBeginFrameSource(
22 base::SingleThreadTaskRunner* task_runner)
23 : scheduler_(scheduler) {
24 if (gfx::FrameTime::TimestampsAreHighRes()) {
25 time_source_ = DelayBasedTimeSourceHighRes::Create(
26 scheduler_->VSyncInterval(), task_runner);
28 time_source_ = DelayBasedTimeSource::Create(scheduler_->VSyncInterval(),
31 time_source_->SetClient(this);
34 Scheduler::SyntheticBeginFrameSource::~SyntheticBeginFrameSource() {
37 void Scheduler::SyntheticBeginFrameSource::CommitVSyncParameters(
38 base::TimeTicks timebase,
39 base::TimeDelta interval) {
40 time_source_->SetTimebaseAndInterval(timebase, interval);
43 void Scheduler::SyntheticBeginFrameSource::SetNeedsBeginFrame(
44 bool needs_begin_frame,
45 std::deque<BeginFrameArgs>* begin_retro_frame_args) {
46 DCHECK(begin_retro_frame_args);
47 base::TimeTicks missed_tick_time =
48 time_source_->SetActive(needs_begin_frame);
49 if (!missed_tick_time.is_null()) {
50 begin_retro_frame_args->push_back(
51 CreateSyntheticBeginFrameArgs(missed_tick_time));
55 bool Scheduler::SyntheticBeginFrameSource::IsActive() const {
56 return time_source_->Active();
59 void Scheduler::SyntheticBeginFrameSource::OnTimerTick() {
60 BeginFrameArgs begin_frame_args(
61 CreateSyntheticBeginFrameArgs(time_source_->LastTickTime()));
62 scheduler_->BeginFrame(begin_frame_args);
65 void Scheduler::SyntheticBeginFrameSource::AsValueInto(
66 base::debug::TracedValue* state) const {
67 time_source_->AsValueInto(state);
71 Scheduler::SyntheticBeginFrameSource::CreateSyntheticBeginFrameArgs(
72 base::TimeTicks frame_time) {
73 base::TimeTicks deadline = time_source_->NextTickTime();
74 return BeginFrameArgs::Create(
75 frame_time, deadline, scheduler_->VSyncInterval());
79 SchedulerClient* client,
80 const SchedulerSettings& scheduler_settings,
81 int layer_tree_host_id,
82 const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner)
83 : settings_(scheduler_settings),
85 layer_tree_host_id_(layer_tree_host_id),
86 impl_task_runner_(impl_task_runner),
87 vsync_interval_(BeginFrameArgs::DefaultInterval()),
88 last_set_needs_begin_frame_(false),
89 begin_unthrottled_frame_posted_(false),
90 begin_retro_frame_posted_(false),
91 state_machine_(scheduler_settings),
92 inside_process_scheduled_actions_(false),
93 inside_action_(SchedulerStateMachine::ACTION_NONE),
95 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
96 "Scheduler::Scheduler",
100 DCHECK(!state_machine_.BeginFrameNeeded());
101 if (settings_.main_frame_before_activation_enabled) {
102 DCHECK(settings_.main_frame_before_draw_enabled);
105 begin_retro_frame_closure_ =
106 base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr());
107 begin_unthrottled_frame_closure_ =
108 base::Bind(&Scheduler::BeginUnthrottledFrame, weak_factory_.GetWeakPtr());
109 begin_impl_frame_deadline_closure_ = base::Bind(
110 &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr());
111 poll_for_draw_triggers_closure_ = base::Bind(
112 &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr());
113 advance_commit_state_closure_ = base::Bind(
114 &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr());
116 if (!settings_.begin_frame_scheduling_enabled) {
117 SetupSyntheticBeginFrames();
121 Scheduler::~Scheduler() {
122 if (synthetic_begin_frame_source_) {
123 synthetic_begin_frame_source_->SetNeedsBeginFrame(false,
124 &begin_retro_frame_args_);
128 void Scheduler::SetupSyntheticBeginFrames() {
129 DCHECK(!synthetic_begin_frame_source_);
130 synthetic_begin_frame_source_.reset(
131 new SyntheticBeginFrameSource(this, impl_task_runner_.get()));
134 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase,
135 base::TimeDelta interval) {
136 // TODO(brianderson): We should not be receiving 0 intervals.
137 if (interval == base::TimeDelta())
138 interval = BeginFrameArgs::DefaultInterval();
139 vsync_interval_ = interval;
140 if (!settings_.begin_frame_scheduling_enabled)
141 synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval);
144 void Scheduler::SetEstimatedParentDrawTime(base::TimeDelta draw_time) {
145 DCHECK_GE(draw_time.ToInternalValue(), 0);
146 estimated_parent_draw_time_ = draw_time;
149 void Scheduler::SetCanStart() {
150 state_machine_.SetCanStart();
151 ProcessScheduledActions();
154 void Scheduler::SetVisible(bool visible) {
155 state_machine_.SetVisible(visible);
156 ProcessScheduledActions();
159 void Scheduler::SetCanDraw(bool can_draw) {
160 state_machine_.SetCanDraw(can_draw);
161 ProcessScheduledActions();
164 void Scheduler::NotifyReadyToActivate() {
165 state_machine_.NotifyReadyToActivate();
166 ProcessScheduledActions();
169 void Scheduler::SetNeedsCommit() {
170 state_machine_.SetNeedsCommit();
171 ProcessScheduledActions();
174 void Scheduler::SetNeedsRedraw() {
175 state_machine_.SetNeedsRedraw();
176 ProcessScheduledActions();
179 void Scheduler::SetNeedsAnimate() {
180 state_machine_.SetNeedsAnimate();
181 ProcessScheduledActions();
184 void Scheduler::SetNeedsManageTiles() {
185 DCHECK(!IsInsideAction(SchedulerStateMachine::ACTION_MANAGE_TILES));
186 state_machine_.SetNeedsManageTiles();
187 ProcessScheduledActions();
190 void Scheduler::SetMaxSwapsPending(int max) {
191 state_machine_.SetMaxSwapsPending(max);
194 void Scheduler::DidSwapBuffers() {
195 state_machine_.DidSwapBuffers();
197 // There is no need to call ProcessScheduledActions here because
198 // swapping should not trigger any new actions.
199 if (!inside_process_scheduled_actions_) {
200 DCHECK_EQ(state_machine_.NextAction(), SchedulerStateMachine::ACTION_NONE);
204 void Scheduler::SetSwapUsedIncompleteTile(bool used_incomplete_tile) {
205 state_machine_.SetSwapUsedIncompleteTile(used_incomplete_tile);
206 ProcessScheduledActions();
209 void Scheduler::DidSwapBuffersComplete() {
210 state_machine_.DidSwapBuffersComplete();
211 ProcessScheduledActions();
214 void Scheduler::SetSmoothnessTakesPriority(bool smoothness_takes_priority) {
215 state_machine_.SetSmoothnessTakesPriority(smoothness_takes_priority);
216 ProcessScheduledActions();
219 void Scheduler::NotifyReadyToCommit() {
220 TRACE_EVENT0("cc", "Scheduler::NotifyReadyToCommit");
221 state_machine_.NotifyReadyToCommit();
222 ProcessScheduledActions();
225 void Scheduler::BeginMainFrameAborted(bool did_handle) {
226 TRACE_EVENT0("cc", "Scheduler::BeginMainFrameAborted");
227 state_machine_.BeginMainFrameAborted(did_handle);
228 ProcessScheduledActions();
231 void Scheduler::DidManageTiles() {
232 state_machine_.DidManageTiles();
235 void Scheduler::DidLoseOutputSurface() {
236 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface");
237 state_machine_.DidLoseOutputSurface();
238 last_set_needs_begin_frame_ = false;
239 if (!settings_.begin_frame_scheduling_enabled) {
240 synthetic_begin_frame_source_->SetNeedsBeginFrame(false,
241 &begin_retro_frame_args_);
243 begin_retro_frame_args_.clear();
244 ProcessScheduledActions();
247 void Scheduler::DidCreateAndInitializeOutputSurface() {
248 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface");
249 DCHECK(!last_set_needs_begin_frame_);
250 DCHECK(begin_impl_frame_deadline_task_.IsCancelled());
251 state_machine_.DidCreateAndInitializeOutputSurface();
252 ProcessScheduledActions();
255 void Scheduler::NotifyBeginMainFrameStarted() {
256 TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted");
257 state_machine_.NotifyBeginMainFrameStarted();
260 base::TimeTicks Scheduler::AnticipatedDrawTime() const {
261 if (!last_set_needs_begin_frame_ ||
262 begin_impl_frame_args_.interval <= base::TimeDelta())
263 return base::TimeTicks();
265 base::TimeTicks now = gfx::FrameTime::Now();
266 base::TimeTicks timebase = std::max(begin_impl_frame_args_.frame_time,
267 begin_impl_frame_args_.deadline);
268 int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval);
269 return timebase + (begin_impl_frame_args_.interval * intervals);
272 base::TimeTicks Scheduler::LastBeginImplFrameTime() {
273 return begin_impl_frame_args_.frame_time;
276 void Scheduler::SetupNextBeginFrameIfNeeded() {
277 bool needs_begin_frame = state_machine_.BeginFrameNeeded();
279 if (settings_.throttle_frame_production) {
280 SetupNextBeginFrameWhenVSyncThrottlingEnabled(needs_begin_frame);
282 SetupNextBeginFrameWhenVSyncThrottlingDisabled(needs_begin_frame);
284 SetupPollingMechanisms(needs_begin_frame);
287 // When we are throttling frame production, we request BeginFrames
288 // from the OutputSurface.
289 void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingEnabled(
290 bool needs_begin_frame) {
291 bool at_end_of_deadline =
292 state_machine_.begin_impl_frame_state() ==
293 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE;
295 bool should_call_set_needs_begin_frame =
296 // Always request the BeginFrame immediately if it wasn't needed before.
297 (needs_begin_frame && !last_set_needs_begin_frame_) ||
298 // Only stop requesting BeginFrames after a deadline.
299 (!needs_begin_frame && last_set_needs_begin_frame_ && at_end_of_deadline);
301 if (should_call_set_needs_begin_frame) {
302 if (settings_.begin_frame_scheduling_enabled) {
303 client_->SetNeedsBeginFrame(needs_begin_frame);
305 synthetic_begin_frame_source_->SetNeedsBeginFrame(
306 needs_begin_frame, &begin_retro_frame_args_);
308 last_set_needs_begin_frame_ = needs_begin_frame;
311 PostBeginRetroFrameIfNeeded();
314 // When we aren't throttling frame production, we initiate a BeginFrame
315 // as soon as one is needed.
316 void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingDisabled(
317 bool needs_begin_frame) {
318 last_set_needs_begin_frame_ = needs_begin_frame;
320 if (!needs_begin_frame || begin_unthrottled_frame_posted_)
323 if (state_machine_.begin_impl_frame_state() !=
324 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE &&
325 state_machine_.begin_impl_frame_state() !=
326 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) {
330 begin_unthrottled_frame_posted_ = true;
331 impl_task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_);
334 // BeginUnthrottledFrame is used when we aren't throttling frame production.
335 // This will usually be because VSync is disabled.
336 void Scheduler::BeginUnthrottledFrame() {
337 DCHECK(!settings_.throttle_frame_production);
338 DCHECK(begin_retro_frame_args_.empty());
340 base::TimeTicks now = gfx::FrameTime::Now();
341 base::TimeTicks deadline = now + vsync_interval_;
343 BeginFrameArgs begin_frame_args =
344 BeginFrameArgs::Create(now, deadline, vsync_interval_);
345 BeginImplFrame(begin_frame_args);
347 begin_unthrottled_frame_posted_ = false;
350 // We may need to poll when we can't rely on BeginFrame to advance certain
351 // state or to avoid deadlock.
352 void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) {
353 bool needs_advance_commit_state_timer = false;
354 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but
355 // aren't expecting any more BeginFrames. This should only be needed by
356 // the synchronous compositor when BeginFrameNeeded is false.
357 if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) {
358 DCHECK(!state_machine_.SupportsProactiveBeginFrame());
359 DCHECK(!needs_begin_frame);
360 if (poll_for_draw_triggers_task_.IsCancelled()) {
361 poll_for_draw_triggers_task_.Reset(poll_for_draw_triggers_closure_);
362 base::TimeDelta delay = begin_impl_frame_args_.IsValid()
363 ? begin_impl_frame_args_.interval
364 : BeginFrameArgs::DefaultInterval();
365 impl_task_runner_->PostDelayedTask(
366 FROM_HERE, poll_for_draw_triggers_task_.callback(), delay);
369 poll_for_draw_triggers_task_.Cancel();
371 // At this point we'd prefer to advance through the commit flow by
372 // drawing a frame, however it's possible that the frame rate controller
373 // will not give us a BeginFrame until the commit completes. See
374 // crbug.com/317430 for an example of a swap ack being held on commit. Thus
375 // we set a repeating timer to poll on ProcessScheduledActions until we
376 // successfully reach BeginFrame. Synchronous compositor does not use
377 // frame rate controller or have the circular wait in the bug.
378 if (IsBeginMainFrameSentOrStarted() &&
379 !settings_.using_synchronous_renderer_compositor) {
380 needs_advance_commit_state_timer = true;
384 if (needs_advance_commit_state_timer) {
385 if (advance_commit_state_task_.IsCancelled() &&
386 begin_impl_frame_args_.IsValid()) {
387 // Since we'd rather get a BeginImplFrame by the normal mechanism, we
388 // set the interval to twice the interval from the previous frame.
389 advance_commit_state_task_.Reset(advance_commit_state_closure_);
390 impl_task_runner_->PostDelayedTask(FROM_HERE,
391 advance_commit_state_task_.callback(),
392 begin_impl_frame_args_.interval * 2);
395 advance_commit_state_task_.Cancel();
399 // BeginFrame is the mechanism that tells us that now is a good time to start
400 // making a frame. Usually this means that user input for the frame is complete.
401 // If the scheduler is busy, we queue the BeginFrame to be handled later as
402 // a BeginRetroFrame.
403 void Scheduler::BeginFrame(const BeginFrameArgs& args) {
404 TRACE_EVENT1("cc", "Scheduler::BeginFrame", "args", args.AsValue());
405 DCHECK(settings_.throttle_frame_production);
407 BeginFrameArgs adjusted_args(args);
408 adjusted_args.deadline -= EstimatedParentDrawTime();
410 bool should_defer_begin_frame;
411 if (settings_.using_synchronous_renderer_compositor) {
412 should_defer_begin_frame = false;
414 should_defer_begin_frame =
415 !begin_retro_frame_args_.empty() || begin_retro_frame_posted_ ||
416 !last_set_needs_begin_frame_ ||
417 (state_machine_.begin_impl_frame_state() !=
418 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
421 if (should_defer_begin_frame) {
422 begin_retro_frame_args_.push_back(adjusted_args);
423 TRACE_EVENT_INSTANT0(
424 "cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD);
428 BeginImplFrame(adjusted_args);
431 // BeginRetroFrame is called for BeginFrames that we've deferred because
432 // the scheduler was in the middle of processing a previous BeginFrame.
433 void Scheduler::BeginRetroFrame() {
434 TRACE_EVENT0("cc", "Scheduler::BeginRetroFrame");
435 DCHECK(!settings_.using_synchronous_renderer_compositor);
436 DCHECK(begin_retro_frame_posted_);
437 begin_retro_frame_posted_ = false;
439 // If there aren't any retroactive BeginFrames, then we've lost the
440 // OutputSurface and should abort.
441 if (begin_retro_frame_args_.empty())
444 // Discard expired BeginRetroFrames
445 // Today, we should always end up with at most one un-expired BeginRetroFrame
446 // because deadlines will not be greater than the next frame time. We don't
447 // DCHECK though because some systems don't always have monotonic timestamps.
448 // TODO(brianderson): In the future, long deadlines could result in us not
449 // draining the queue if we don't catch up. If we consistently can't catch
450 // up, our fallback should be to lower our frame rate.
451 base::TimeTicks now = gfx::FrameTime::Now();
452 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate();
453 while (!begin_retro_frame_args_.empty() &&
454 now > AdjustedBeginImplFrameDeadline(begin_retro_frame_args_.front(),
455 draw_duration_estimate)) {
457 "Scheduler::BeginRetroFrame discarding",
459 begin_retro_frame_args_.front().frame_time);
460 begin_retro_frame_args_.pop_front();
463 if (begin_retro_frame_args_.empty()) {
464 DCHECK(settings_.throttle_frame_production);
465 TRACE_EVENT_INSTANT0("cc",
466 "Scheduler::BeginRetroFrames all expired",
467 TRACE_EVENT_SCOPE_THREAD);
469 BeginImplFrame(begin_retro_frame_args_.front());
470 begin_retro_frame_args_.pop_front();
474 // There could be a race between the posted BeginRetroFrame and a new
475 // BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame
476 // will check if there is a pending BeginRetroFrame to ensure we handle
477 // BeginFrames in FIFO order.
478 void Scheduler::PostBeginRetroFrameIfNeeded() {
479 if (!last_set_needs_begin_frame_)
482 if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_)
485 // begin_retro_frame_args_ should always be empty for the
486 // synchronous compositor.
487 DCHECK(!settings_.using_synchronous_renderer_compositor);
489 if (state_machine_.begin_impl_frame_state() !=
490 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE)
493 begin_retro_frame_posted_ = true;
494 impl_task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_);
497 // BeginImplFrame starts a compositor frame that will wait up until a deadline
498 // for a BeginMainFrame+activation to complete before it times out and draws
499 // any asynchronous animation and scroll/pinch updates.
500 void Scheduler::BeginImplFrame(const BeginFrameArgs& args) {
501 TRACE_EVENT1("cc", "Scheduler::BeginImplFrame", "args", args.AsValue());
502 DCHECK(state_machine_.begin_impl_frame_state() ==
503 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
504 DCHECK(state_machine_.HasInitializedOutputSurface());
506 advance_commit_state_task_.Cancel();
508 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate();
509 begin_impl_frame_args_ = args;
510 begin_impl_frame_args_.deadline -= draw_duration_estimate;
512 if (!state_machine_.smoothness_takes_priority() &&
513 state_machine_.MainThreadIsInHighLatencyMode() &&
514 CanCommitAndActivateBeforeDeadline()) {
515 state_machine_.SetSkipNextBeginMainFrameToReduceLatency();
518 client_->WillBeginImplFrame(begin_impl_frame_args_);
519 state_machine_.OnBeginImplFrame(begin_impl_frame_args_);
520 devtools_instrumentation::DidBeginFrame(layer_tree_host_id_);
522 ProcessScheduledActions();
524 state_machine_.OnBeginImplFrameDeadlinePending();
525 ScheduleBeginImplFrameDeadline(
526 AdjustedBeginImplFrameDeadline(args, draw_duration_estimate));
529 base::TimeTicks Scheduler::AdjustedBeginImplFrameDeadline(
530 const BeginFrameArgs& args,
531 base::TimeDelta draw_duration_estimate) const {
532 if (settings_.using_synchronous_renderer_compositor) {
533 // The synchronous compositor needs to draw right away.
534 return base::TimeTicks();
535 } else if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
536 // We are ready to draw a new active tree immediately.
537 return base::TimeTicks();
538 } else if (state_machine_.needs_redraw()) {
539 // We have an animation or fast input path on the impl thread that wants
540 // to draw, so don't wait too long for a new active tree.
541 return args.deadline - draw_duration_estimate;
543 // The impl thread doesn't have anything it wants to draw and we are just
544 // waiting for a new active tree, so post the deadline for the next
545 // expected BeginImplFrame start. This allows us to draw immediately when
546 // there is a new active tree, instead of waiting for the next
548 // TODO(brianderson): Handle long deadlines (that are past the next frame's
549 // frame time) properly instead of using this hack.
550 return args.frame_time + args.interval;
554 void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) {
555 if (settings_.using_synchronous_renderer_compositor) {
556 // The synchronous renderer compositor has to make its GL calls
558 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks
559 // so the sychronous renderer compositor can take advantage of splitting
560 // up the BeginImplFrame and deadline as well.
561 OnBeginImplFrameDeadline();
564 begin_impl_frame_deadline_task_.Cancel();
565 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_);
567 base::TimeDelta delta = deadline - gfx::FrameTime::Now();
568 if (delta <= base::TimeDelta())
569 delta = base::TimeDelta();
570 impl_task_runner_->PostDelayedTask(
571 FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta);
574 void Scheduler::OnBeginImplFrameDeadline() {
575 TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline");
576 begin_impl_frame_deadline_task_.Cancel();
578 // We split the deadline actions up into two phases so the state machine
579 // has a chance to trigger actions that should occur durring and after
580 // the deadline separately. For example:
581 // * Sending the BeginMainFrame will not occur after the deadline in
582 // order to wait for more user-input before starting the next commit.
583 // * Creating a new OuputSurface will not occur during the deadline in
584 // order to allow the state machine to "settle" first.
585 state_machine_.OnBeginImplFrameDeadline();
586 ProcessScheduledActions();
587 state_machine_.OnBeginImplFrameIdle();
588 ProcessScheduledActions();
590 client_->DidBeginImplFrameDeadline();
593 void Scheduler::PollForAnticipatedDrawTriggers() {
594 TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers");
595 poll_for_draw_triggers_task_.Cancel();
596 state_machine_.DidEnterPollForAnticipatedDrawTriggers();
597 ProcessScheduledActions();
598 state_machine_.DidLeavePollForAnticipatedDrawTriggers();
601 void Scheduler::PollToAdvanceCommitState() {
602 TRACE_EVENT0("cc", "Scheduler::PollToAdvanceCommitState");
603 advance_commit_state_task_.Cancel();
604 ProcessScheduledActions();
607 bool Scheduler::IsBeginMainFrameSent() const {
608 return state_machine_.commit_state() ==
609 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT;
612 void Scheduler::DrawAndSwapIfPossible() {
613 DrawResult result = client_->ScheduledActionDrawAndSwapIfPossible();
614 state_machine_.DidDrawIfPossibleCompleted(result);
617 void Scheduler::ProcessScheduledActions() {
618 // We do not allow ProcessScheduledActions to be recursive.
619 // The top-level call will iteratively execute the next action for us anyway.
620 if (inside_process_scheduled_actions_)
623 base::AutoReset<bool> mark_inside(&inside_process_scheduled_actions_, true);
625 SchedulerStateMachine::Action action;
627 action = state_machine_.NextAction();
628 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
629 "SchedulerStateMachine",
632 state_machine_.UpdateState(action);
633 base::AutoReset<SchedulerStateMachine::Action>
634 mark_inside_action(&inside_action_, action);
636 case SchedulerStateMachine::ACTION_NONE:
638 case SchedulerStateMachine::ACTION_ANIMATE:
639 client_->ScheduledActionAnimate();
641 case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME:
642 client_->ScheduledActionSendBeginMainFrame();
644 case SchedulerStateMachine::ACTION_COMMIT:
645 client_->ScheduledActionCommit();
647 case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES:
648 client_->ScheduledActionUpdateVisibleTiles();
650 case SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE:
651 client_->ScheduledActionActivateSyncTree();
653 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
654 DrawAndSwapIfPossible();
656 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED:
657 client_->ScheduledActionDrawAndSwapForced();
659 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT:
660 // No action is actually performed, but this allows the state machine to
661 // advance out of its waiting to draw state without actually drawing.
663 case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
664 client_->ScheduledActionBeginOutputSurfaceCreation();
666 case SchedulerStateMachine::ACTION_MANAGE_TILES:
667 client_->ScheduledActionManageTiles();
670 } while (action != SchedulerStateMachine::ACTION_NONE);
672 SetupNextBeginFrameIfNeeded();
673 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime());
675 if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
676 DCHECK(!settings_.using_synchronous_renderer_compositor);
677 ScheduleBeginImplFrameDeadline(base::TimeTicks());
681 bool Scheduler::WillDrawIfNeeded() const {
682 return !state_machine_.PendingDrawsShouldBeAborted();
685 scoped_refptr<base::debug::ConvertableToTraceFormat> Scheduler::AsValue()
687 scoped_refptr<base::debug::TracedValue> state =
688 new base::debug::TracedValue();
689 state->BeginDictionary("state_machine");
690 state_machine_.AsValueInto(state);
691 state->EndDictionary();
692 if (synthetic_begin_frame_source_) {
693 state->BeginDictionary("synthetic_begin_frame_source_");
694 synthetic_begin_frame_source_->AsValueInto(state);
695 state->EndDictionary();
698 state->BeginDictionary("scheduler_state");
700 "time_until_anticipated_draw_time_ms",
701 (AnticipatedDrawTime() - base::TimeTicks::Now()).InMillisecondsF());
702 state->SetDouble("vsync_interval_ms", vsync_interval_.InMillisecondsF());
703 state->SetDouble("estimated_parent_draw_time_ms",
704 estimated_parent_draw_time_.InMillisecondsF());
705 state->SetBoolean("last_set_needs_begin_frame_", last_set_needs_begin_frame_);
706 state->SetBoolean("begin_unthrottled_frame_posted_",
707 begin_unthrottled_frame_posted_);
708 state->SetBoolean("begin_retro_frame_posted_", begin_retro_frame_posted_);
709 state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size());
710 state->SetBoolean("begin_impl_frame_deadline_task_",
711 !begin_impl_frame_deadline_task_.IsCancelled());
712 state->SetBoolean("poll_for_draw_triggers_task_",
713 !poll_for_draw_triggers_task_.IsCancelled());
714 state->SetBoolean("advance_commit_state_task_",
715 !advance_commit_state_task_.IsCancelled());
716 state->BeginDictionary("begin_impl_frame_args");
717 begin_impl_frame_args_.AsValueInto(state);
718 state->EndDictionary();
720 state->EndDictionary();
722 state->BeginDictionary("client_state");
723 state->SetDouble("draw_duration_estimate_ms",
724 client_->DrawDurationEstimate().InMillisecondsF());
726 "begin_main_frame_to_commit_duration_estimate_ms",
727 client_->BeginMainFrameToCommitDurationEstimate().InMillisecondsF());
729 "commit_to_activate_duration_estimate_ms",
730 client_->CommitToActivateDurationEstimate().InMillisecondsF());
731 state->EndDictionary();
735 bool Scheduler::CanCommitAndActivateBeforeDeadline() const {
736 // Check if the main thread computation and commit can be finished before the
737 // impl thread's deadline.
738 base::TimeTicks estimated_draw_time =
739 begin_impl_frame_args_.frame_time +
740 client_->BeginMainFrameToCommitDurationEstimate() +
741 client_->CommitToActivateDurationEstimate();
744 TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
745 "CanCommitAndActivateBeforeDeadline",
746 "time_left_after_drawing_ms",
747 (begin_impl_frame_args_.deadline - estimated_draw_time).InMillisecondsF(),
751 return estimated_draw_time < begin_impl_frame_args_.deadline;
754 bool Scheduler::IsBeginMainFrameSentOrStarted() const {
755 return (state_machine_.commit_state() ==
756 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT ||
757 state_machine_.commit_state() ==
758 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED);