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/logging.h"
11 #include "cc/debug/devtools_instrumentation.h"
12 #include "cc/debug/traced_value.h"
13 #include "cc/scheduler/delay_based_time_source.h"
14 #include "ui/gfx/frame_time.h"
18 class SyntheticBeginFrameSource
: public TimeSourceClient
{
20 SyntheticBeginFrameSource(Scheduler
* scheduler
,
21 base::SingleThreadTaskRunner
* task_runner
)
22 : scheduler_(scheduler
) {
23 if (gfx::FrameTime::TimestampsAreHighRes()) {
24 time_source_
= DelayBasedTimeSourceHighRes::Create(
25 scheduler_
->VSyncInterval(), task_runner
);
27 time_source_
= DelayBasedTimeSource::Create(scheduler_
->VSyncInterval(),
30 time_source_
->SetClient(this);
33 virtual ~SyntheticBeginFrameSource() {}
35 // Updates the phase and frequency of the timer.
36 void CommitVSyncParameters(base::TimeTicks timebase
,
37 base::TimeDelta interval
) {
38 time_source_
->SetTimebaseAndInterval(timebase
, interval
);
41 // Activates future BeginFrames and, if activating, pushes the most
42 // recently missed BeginFrame to the back of a retroactive queue.
43 void SetNeedsBeginFrame(bool needs_begin_frame
,
44 std::deque
<BeginFrameArgs
>* begin_retro_frame_args
) {
45 base::TimeTicks missed_tick_time
=
46 time_source_
->SetActive(needs_begin_frame
);
47 if (!missed_tick_time
.is_null()) {
48 begin_retro_frame_args
->push_back(
49 CreateSyntheticBeginFrameArgs(missed_tick_time
));
53 // TimeSourceClient implementation of OnTimerTick triggers a BeginFrame.
54 virtual void OnTimerTick() OVERRIDE
{
55 BeginFrameArgs
begin_frame_args(
56 CreateSyntheticBeginFrameArgs(time_source_
->LastTickTime()));
57 scheduler_
->BeginFrame(begin_frame_args
);
61 BeginFrameArgs
CreateSyntheticBeginFrameArgs(base::TimeTicks frame_time
) {
62 base::TimeTicks deadline
=
63 time_source_
->NextTickTime() - scheduler_
->EstimatedParentDrawTime();
64 return BeginFrameArgs::Create(
65 frame_time
, deadline
, scheduler_
->VSyncInterval());
68 Scheduler
* scheduler_
;
69 scoped_refptr
<TimeSource
> time_source_
;
73 SchedulerClient
* client
,
74 const SchedulerSettings
& scheduler_settings
,
75 int layer_tree_host_id
,
76 const scoped_refptr
<base::SingleThreadTaskRunner
>& impl_task_runner
)
77 : settings_(scheduler_settings
),
79 layer_tree_host_id_(layer_tree_host_id
),
80 impl_task_runner_(impl_task_runner
),
81 vsync_interval_(BeginFrameArgs::DefaultInterval()),
82 last_set_needs_begin_frame_(false),
83 begin_unthrottled_frame_posted_(false),
84 begin_retro_frame_posted_(false),
85 state_machine_(scheduler_settings
),
86 inside_process_scheduled_actions_(false),
87 inside_action_(SchedulerStateMachine::ACTION_NONE
),
90 DCHECK(!state_machine_
.BeginFrameNeeded());
91 if (settings_
.main_frame_before_activation_enabled
) {
92 DCHECK(settings_
.main_frame_before_draw_enabled
);
95 begin_retro_frame_closure_
=
96 base::Bind(&Scheduler::BeginRetroFrame
, weak_factory_
.GetWeakPtr());
97 begin_unthrottled_frame_closure_
=
98 base::Bind(&Scheduler::BeginUnthrottledFrame
, weak_factory_
.GetWeakPtr());
99 begin_impl_frame_deadline_closure_
= base::Bind(
100 &Scheduler::OnBeginImplFrameDeadline
, weak_factory_
.GetWeakPtr());
101 poll_for_draw_triggers_closure_
= base::Bind(
102 &Scheduler::PollForAnticipatedDrawTriggers
, weak_factory_
.GetWeakPtr());
103 advance_commit_state_closure_
= base::Bind(
104 &Scheduler::PollToAdvanceCommitState
, weak_factory_
.GetWeakPtr());
106 if (!settings_
.begin_frame_scheduling_enabled
) {
107 SetupSyntheticBeginFrames();
111 Scheduler::~Scheduler() {
112 if (synthetic_begin_frame_source_
) {
113 synthetic_begin_frame_source_
->SetNeedsBeginFrame(false,
114 &begin_retro_frame_args_
);
118 void Scheduler::SetupSyntheticBeginFrames() {
119 DCHECK(!synthetic_begin_frame_source_
);
120 synthetic_begin_frame_source_
.reset(
121 new SyntheticBeginFrameSource(this, impl_task_runner_
.get()));
124 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase
,
125 base::TimeDelta interval
) {
126 // TODO(brianderson): We should not be receiving 0 intervals.
127 if (interval
== base::TimeDelta())
128 interval
= BeginFrameArgs::DefaultInterval();
129 vsync_interval_
= interval
;
130 if (!settings_
.begin_frame_scheduling_enabled
)
131 synthetic_begin_frame_source_
->CommitVSyncParameters(timebase
, interval
);
134 void Scheduler::SetEstimatedParentDrawTime(base::TimeDelta draw_time
) {
135 estimated_parent_draw_time_
= draw_time
;
138 void Scheduler::SetCanStart() {
139 state_machine_
.SetCanStart();
140 ProcessScheduledActions();
143 void Scheduler::SetVisible(bool visible
) {
144 state_machine_
.SetVisible(visible
);
145 ProcessScheduledActions();
148 void Scheduler::SetCanDraw(bool can_draw
) {
149 state_machine_
.SetCanDraw(can_draw
);
150 ProcessScheduledActions();
153 void Scheduler::NotifyReadyToActivate() {
154 state_machine_
.NotifyReadyToActivate();
155 ProcessScheduledActions();
158 void Scheduler::ActivatePendingTree() {
159 client_
->ScheduledActionActivatePendingTree();
162 void Scheduler::SetNeedsCommit() {
163 state_machine_
.SetNeedsCommit();
164 ProcessScheduledActions();
167 void Scheduler::SetNeedsForcedCommitForReadback() {
168 state_machine_
.SetNeedsForcedCommitForReadback();
169 ProcessScheduledActions();
172 void Scheduler::SetNeedsRedraw() {
173 state_machine_
.SetNeedsRedraw();
174 ProcessScheduledActions();
177 void Scheduler::SetNeedsAnimate() {
178 state_machine_
.SetNeedsAnimate();
179 ProcessScheduledActions();
182 void Scheduler::SetNeedsManageTiles() {
183 DCHECK(!IsInsideAction(SchedulerStateMachine::ACTION_MANAGE_TILES
));
184 state_machine_
.SetNeedsManageTiles();
185 ProcessScheduledActions();
188 void Scheduler::SetMaxSwapsPending(int max
) {
189 state_machine_
.SetMaxSwapsPending(max
);
192 void Scheduler::DidSwapBuffers() {
193 state_machine_
.DidSwapBuffers();
194 // There is no need to call ProcessScheduledActions here because
195 // swapping should not trigger any new actions.
196 if (!inside_process_scheduled_actions_
) {
197 DCHECK_EQ(state_machine_
.NextAction(), SchedulerStateMachine::ACTION_NONE
);
201 void Scheduler::SetSwapUsedIncompleteTile(bool used_incomplete_tile
) {
202 state_machine_
.SetSwapUsedIncompleteTile(used_incomplete_tile
);
203 ProcessScheduledActions();
206 void Scheduler::DidSwapBuffersComplete() {
207 state_machine_
.DidSwapBuffersComplete();
208 ProcessScheduledActions();
211 void Scheduler::SetSmoothnessTakesPriority(bool smoothness_takes_priority
) {
212 state_machine_
.SetSmoothnessTakesPriority(smoothness_takes_priority
);
213 ProcessScheduledActions();
216 void Scheduler::NotifyReadyToCommit() {
217 TRACE_EVENT0("cc", "Scheduler::NotifyReadyToCommit");
218 state_machine_
.NotifyReadyToCommit();
219 ProcessScheduledActions();
222 void Scheduler::BeginMainFrameAborted(bool did_handle
) {
223 TRACE_EVENT0("cc", "Scheduler::BeginMainFrameAborted");
224 state_machine_
.BeginMainFrameAborted(did_handle
);
225 ProcessScheduledActions();
228 void Scheduler::DidManageTiles() {
229 state_machine_
.DidManageTiles();
232 void Scheduler::DidLoseOutputSurface() {
233 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface");
234 state_machine_
.DidLoseOutputSurface();
235 last_set_needs_begin_frame_
= false;
236 begin_retro_frame_args_
.clear();
237 ProcessScheduledActions();
240 void Scheduler::DidCreateAndInitializeOutputSurface() {
241 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface");
242 DCHECK(!last_set_needs_begin_frame_
);
243 DCHECK(begin_impl_frame_deadline_task_
.IsCancelled());
244 state_machine_
.DidCreateAndInitializeOutputSurface();
245 ProcessScheduledActions();
248 void Scheduler::NotifyBeginMainFrameStarted() {
249 TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted");
250 state_machine_
.NotifyBeginMainFrameStarted();
253 base::TimeTicks
Scheduler::AnticipatedDrawTime() const {
254 if (!last_set_needs_begin_frame_
||
255 begin_impl_frame_args_
.interval
<= base::TimeDelta())
256 return base::TimeTicks();
258 base::TimeTicks now
= gfx::FrameTime::Now();
259 base::TimeTicks timebase
= std::max(begin_impl_frame_args_
.frame_time
,
260 begin_impl_frame_args_
.deadline
);
261 int64 intervals
= 1 + ((now
- timebase
) / begin_impl_frame_args_
.interval
);
262 return timebase
+ (begin_impl_frame_args_
.interval
* intervals
);
265 base::TimeTicks
Scheduler::LastBeginImplFrameTime() {
266 return begin_impl_frame_args_
.frame_time
;
269 void Scheduler::SetupNextBeginFrameIfNeeded() {
270 bool needs_begin_frame
= state_machine_
.BeginFrameNeeded();
272 if (settings_
.throttle_frame_production
) {
273 SetupNextBeginFrameWhenVSyncThrottlingEnabled(needs_begin_frame
);
275 SetupNextBeginFrameWhenVSyncThrottlingDisabled(needs_begin_frame
);
277 SetupPollingMechanisms(needs_begin_frame
);
280 // When we are throttling frame production, we request BeginFrames
281 // from the OutputSurface.
282 void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingEnabled(
283 bool needs_begin_frame
) {
284 bool at_end_of_deadline
=
285 state_machine_
.begin_impl_frame_state() ==
286 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE
;
288 bool should_call_set_needs_begin_frame
=
289 // Always request the BeginFrame immediately if it wasn't needed before.
290 (needs_begin_frame
&& !last_set_needs_begin_frame_
) ||
291 // Only stop requesting BeginFrames after a deadline.
292 (!needs_begin_frame
&& last_set_needs_begin_frame_
&& at_end_of_deadline
);
294 if (should_call_set_needs_begin_frame
) {
295 if (settings_
.begin_frame_scheduling_enabled
) {
296 client_
->SetNeedsBeginFrame(needs_begin_frame
);
298 synthetic_begin_frame_source_
->SetNeedsBeginFrame(
299 needs_begin_frame
, &begin_retro_frame_args_
);
301 last_set_needs_begin_frame_
= needs_begin_frame
;
304 PostBeginRetroFrameIfNeeded();
307 // When we aren't throttling frame production, we initiate a BeginFrame
308 // as soon as one is needed.
309 void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingDisabled(
310 bool needs_begin_frame
) {
311 last_set_needs_begin_frame_
= needs_begin_frame
;
313 if (!needs_begin_frame
|| begin_unthrottled_frame_posted_
)
316 if (state_machine_
.begin_impl_frame_state() !=
317 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE
&&
318 state_machine_
.begin_impl_frame_state() !=
319 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE
) {
323 begin_unthrottled_frame_posted_
= true;
324 impl_task_runner_
->PostTask(FROM_HERE
, begin_unthrottled_frame_closure_
);
327 // BeginUnthrottledFrame is used when we aren't throttling frame production.
328 // This will usually be because VSync is disabled.
329 void Scheduler::BeginUnthrottledFrame() {
330 DCHECK(!settings_
.throttle_frame_production
);
331 DCHECK(begin_retro_frame_args_
.empty());
333 base::TimeTicks now
= gfx::FrameTime::Now();
334 base::TimeTicks deadline
= now
+ vsync_interval_
;
336 BeginFrameArgs begin_frame_args
=
337 BeginFrameArgs::Create(now
, deadline
, vsync_interval_
);
338 BeginImplFrame(begin_frame_args
);
340 begin_unthrottled_frame_posted_
= false;
343 // We may need to poll when we can't rely on BeginFrame to advance certain
344 // state or to avoid deadlock.
345 void Scheduler::SetupPollingMechanisms(bool needs_begin_frame
) {
346 bool needs_advance_commit_state_timer
= false;
347 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but
348 // aren't expecting any more BeginFrames. This should only be needed by
349 // the synchronous compositor when BeginFrameNeeded is false.
350 if (state_machine_
.ShouldPollForAnticipatedDrawTriggers()) {
351 DCHECK(!state_machine_
.SupportsProactiveBeginFrame());
352 DCHECK(!needs_begin_frame
);
353 if (poll_for_draw_triggers_task_
.IsCancelled()) {
354 poll_for_draw_triggers_task_
.Reset(poll_for_draw_triggers_closure_
);
355 base::TimeDelta delay
= begin_impl_frame_args_
.IsValid()
356 ? begin_impl_frame_args_
.interval
357 : BeginFrameArgs::DefaultInterval();
358 impl_task_runner_
->PostDelayedTask(
359 FROM_HERE
, poll_for_draw_triggers_task_
.callback(), delay
);
362 poll_for_draw_triggers_task_
.Cancel();
364 // At this point we'd prefer to advance through the commit flow by
365 // drawing a frame, however it's possible that the frame rate controller
366 // will not give us a BeginFrame until the commit completes. See
367 // crbug.com/317430 for an example of a swap ack being held on commit. Thus
368 // we set a repeating timer to poll on ProcessScheduledActions until we
369 // successfully reach BeginFrame. Synchronous compositor does not use
370 // frame rate controller or have the circular wait in the bug.
371 if (IsBeginMainFrameSentOrStarted() &&
372 !settings_
.using_synchronous_renderer_compositor
) {
373 needs_advance_commit_state_timer
= true;
377 if (needs_advance_commit_state_timer
) {
378 if (advance_commit_state_task_
.IsCancelled() &&
379 begin_impl_frame_args_
.IsValid()) {
380 // Since we'd rather get a BeginImplFrame by the normal mechanism, we
381 // set the interval to twice the interval from the previous frame.
382 advance_commit_state_task_
.Reset(advance_commit_state_closure_
);
383 impl_task_runner_
->PostDelayedTask(FROM_HERE
,
384 advance_commit_state_task_
.callback(),
385 begin_impl_frame_args_
.interval
* 2);
388 advance_commit_state_task_
.Cancel();
392 // BeginFrame is the mechanism that tells us that now is a good time to start
393 // making a frame. Usually this means that user input for the frame is complete.
394 // If the scheduler is busy, we queue the BeginFrame to be handled later as
395 // a BeginRetroFrame.
396 void Scheduler::BeginFrame(const BeginFrameArgs
& args
) {
397 TRACE_EVENT1("cc", "Scheduler::BeginFrame", "frame_time", args
.frame_time
);
398 DCHECK(settings_
.throttle_frame_production
);
400 bool should_defer_begin_frame
;
401 if (settings_
.using_synchronous_renderer_compositor
) {
402 should_defer_begin_frame
= false;
404 should_defer_begin_frame
=
405 !begin_retro_frame_args_
.empty() || begin_retro_frame_posted_
||
406 !last_set_needs_begin_frame_
||
407 (state_machine_
.begin_impl_frame_state() !=
408 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE
);
411 if (should_defer_begin_frame
) {
412 begin_retro_frame_args_
.push_back(args
);
413 TRACE_EVENT_INSTANT0(
414 "cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD
);
418 BeginImplFrame(args
);
421 // BeginRetroFrame is called for BeginFrames that we've deferred because
422 // the scheduler was in the middle of processing a previous BeginFrame.
423 void Scheduler::BeginRetroFrame() {
424 TRACE_EVENT0("cc", "Scheduler::BeginRetroFrame");
425 DCHECK(!settings_
.using_synchronous_renderer_compositor
);
426 DCHECK(begin_retro_frame_posted_
);
427 begin_retro_frame_posted_
= false;
429 // If there aren't any retroactive BeginFrames, then we've lost the
430 // OutputSurface and should abort.
431 if (begin_retro_frame_args_
.empty())
434 // Discard expired BeginRetroFrames
435 // Today, we should always end up with at most one un-expired BeginRetroFrame
436 // because deadlines will not be greater than the next frame time. We don't
437 // DCHECK though because some systems don't always have monotonic timestamps.
438 // TODO(brianderson): In the future, long deadlines could result in us not
439 // draining the queue if we don't catch up. If we consistently can't catch
440 // up, our fallback should be to lower our frame rate.
441 base::TimeTicks now
= gfx::FrameTime::Now();
442 base::TimeDelta draw_duration_estimate
= client_
->DrawDurationEstimate();
443 while (!begin_retro_frame_args_
.empty() &&
444 now
> AdjustedBeginImplFrameDeadline(begin_retro_frame_args_
.front(),
445 draw_duration_estimate
)) {
447 "Scheduler::BeginRetroFrame discarding",
449 begin_retro_frame_args_
.front().frame_time
);
450 begin_retro_frame_args_
.pop_front();
453 if (begin_retro_frame_args_
.empty()) {
454 DCHECK(settings_
.throttle_frame_production
);
455 TRACE_EVENT_INSTANT0("cc",
456 "Scheduler::BeginRetroFrames all expired",
457 TRACE_EVENT_SCOPE_THREAD
);
459 BeginImplFrame(begin_retro_frame_args_
.front());
460 begin_retro_frame_args_
.pop_front();
464 // There could be a race between the posted BeginRetroFrame and a new
465 // BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame
466 // will check if there is a pending BeginRetroFrame to ensure we handle
467 // BeginFrames in FIFO order.
468 void Scheduler::PostBeginRetroFrameIfNeeded() {
469 if (!last_set_needs_begin_frame_
)
472 if (begin_retro_frame_args_
.empty() || begin_retro_frame_posted_
)
475 // begin_retro_frame_args_ should always be empty for the
476 // synchronous compositor.
477 DCHECK(!settings_
.using_synchronous_renderer_compositor
);
479 if (state_machine_
.begin_impl_frame_state() !=
480 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE
)
483 begin_retro_frame_posted_
= true;
484 impl_task_runner_
->PostTask(FROM_HERE
, begin_retro_frame_closure_
);
487 // BeginImplFrame starts a compositor frame that will wait up until a deadline
488 // for a BeginMainFrame+activation to complete before it times out and draws
489 // any asynchronous animation and scroll/pinch updates.
490 void Scheduler::BeginImplFrame(const BeginFrameArgs
& args
) {
492 "cc", "Scheduler::BeginImplFrame", "frame_time", args
.frame_time
);
493 DCHECK(state_machine_
.begin_impl_frame_state() ==
494 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE
);
495 DCHECK(state_machine_
.HasInitializedOutputSurface());
497 advance_commit_state_task_
.Cancel();
499 base::TimeDelta draw_duration_estimate
= client_
->DrawDurationEstimate();
500 begin_impl_frame_args_
= args
;
501 begin_impl_frame_args_
.deadline
-= draw_duration_estimate
;
503 if (!state_machine_
.smoothness_takes_priority() &&
504 state_machine_
.MainThreadIsInHighLatencyMode() &&
505 CanCommitAndActivateBeforeDeadline()) {
506 state_machine_
.SetSkipNextBeginMainFrameToReduceLatency();
509 client_
->WillBeginImplFrame(begin_impl_frame_args_
);
510 state_machine_
.OnBeginImplFrame(begin_impl_frame_args_
);
511 devtools_instrumentation::DidBeginFrame(layer_tree_host_id_
);
513 ProcessScheduledActions();
515 state_machine_
.OnBeginImplFrameDeadlinePending();
516 ScheduleBeginImplFrameDeadline(
517 AdjustedBeginImplFrameDeadline(args
, draw_duration_estimate
));
520 base::TimeTicks
Scheduler::AdjustedBeginImplFrameDeadline(
521 const BeginFrameArgs
& args
,
522 base::TimeDelta draw_duration_estimate
) const {
523 if (settings_
.using_synchronous_renderer_compositor
) {
524 // The synchronous compositor needs to draw right away.
525 return base::TimeTicks();
526 } else if (state_machine_
.ShouldTriggerBeginImplFrameDeadlineEarly()) {
527 // We are ready to draw a new active tree immediately.
528 return base::TimeTicks();
529 } else if (state_machine_
.needs_redraw()) {
530 // We have an animation or fast input path on the impl thread that wants
531 // to draw, so don't wait too long for a new active tree.
532 return args
.deadline
- draw_duration_estimate
;
534 // The impl thread doesn't have anything it wants to draw and we are just
535 // waiting for a new active tree, so post the deadline for the next
536 // expected BeginImplFrame start. This allows us to draw immediately when
537 // there is a new active tree, instead of waiting for the next
539 // TODO(brianderson): Handle long deadlines (that are past the next frame's
540 // frame time) properly instead of using this hack.
541 return args
.frame_time
+ args
.interval
;
545 void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline
) {
546 if (settings_
.using_synchronous_renderer_compositor
) {
547 // The synchronous renderer compositor has to make its GL calls
549 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks
550 // so the sychronous renderer compositor can take advantage of splitting
551 // up the BeginImplFrame and deadline as well.
552 OnBeginImplFrameDeadline();
555 begin_impl_frame_deadline_task_
.Cancel();
556 begin_impl_frame_deadline_task_
.Reset(begin_impl_frame_deadline_closure_
);
558 base::TimeDelta delta
= deadline
- gfx::FrameTime::Now();
559 if (delta
<= base::TimeDelta())
560 delta
= base::TimeDelta();
561 impl_task_runner_
->PostDelayedTask(
562 FROM_HERE
, begin_impl_frame_deadline_task_
.callback(), delta
);
565 void Scheduler::OnBeginImplFrameDeadline() {
566 TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline");
567 begin_impl_frame_deadline_task_
.Cancel();
569 // We split the deadline actions up into two phases so the state machine
570 // has a chance to trigger actions that should occur durring and after
571 // the deadline separately. For example:
572 // * Sending the BeginMainFrame will not occur after the deadline in
573 // order to wait for more user-input before starting the next commit.
574 // * Creating a new OuputSurface will not occur during the deadline in
575 // order to allow the state machine to "settle" first.
576 state_machine_
.OnBeginImplFrameDeadline();
577 ProcessScheduledActions();
578 state_machine_
.OnBeginImplFrameIdle();
579 ProcessScheduledActions();
581 client_
->DidBeginImplFrameDeadline();
584 void Scheduler::PollForAnticipatedDrawTriggers() {
585 TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers");
586 poll_for_draw_triggers_task_
.Cancel();
587 state_machine_
.DidEnterPollForAnticipatedDrawTriggers();
588 ProcessScheduledActions();
589 state_machine_
.DidLeavePollForAnticipatedDrawTriggers();
592 void Scheduler::PollToAdvanceCommitState() {
593 TRACE_EVENT0("cc", "Scheduler::PollToAdvanceCommitState");
594 advance_commit_state_task_
.Cancel();
595 ProcessScheduledActions();
598 bool Scheduler::IsBeginMainFrameSent() const {
599 return state_machine_
.commit_state() ==
600 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT
;
603 void Scheduler::DrawAndSwapIfPossible() {
604 DrawSwapReadbackResult result
=
605 client_
->ScheduledActionDrawAndSwapIfPossible();
606 state_machine_
.DidDrawIfPossibleCompleted(result
.draw_result
);
609 void Scheduler::DrawAndSwapForced() {
610 client_
->ScheduledActionDrawAndSwapForced();
613 void Scheduler::DrawAndReadback() {
614 DrawSwapReadbackResult result
= client_
->ScheduledActionDrawAndReadback();
615 DCHECK(!result
.did_request_swap
);
618 void Scheduler::ProcessScheduledActions() {
619 // We do not allow ProcessScheduledActions to be recursive.
620 // The top-level call will iteratively execute the next action for us anyway.
621 if (inside_process_scheduled_actions_
)
624 base::AutoReset
<bool> mark_inside(&inside_process_scheduled_actions_
, true);
626 SchedulerStateMachine::Action action
;
628 state_machine_
.CheckInvariants();
629 action
= state_machine_
.NextAction();
630 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
631 "SchedulerStateMachine",
633 TracedValue::FromValue(StateAsValue().release()));
634 state_machine_
.UpdateState(action
);
635 base::AutoReset
<SchedulerStateMachine::Action
>
636 mark_inside_action(&inside_action_
, action
);
638 case SchedulerStateMachine::ACTION_NONE
:
640 case SchedulerStateMachine::ACTION_ANIMATE
:
641 client_
->ScheduledActionAnimate();
643 case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME
:
644 client_
->ScheduledActionSendBeginMainFrame();
646 case SchedulerStateMachine::ACTION_COMMIT
:
647 client_
->ScheduledActionCommit();
649 case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES
:
650 client_
->ScheduledActionUpdateVisibleTiles();
652 case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE
:
653 ActivatePendingTree();
655 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE
:
656 DrawAndSwapIfPossible();
658 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED
:
661 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT
:
662 // No action is actually performed, but this allows the state machine to
663 // advance out of its waiting to draw state without actually drawing.
665 case SchedulerStateMachine::ACTION_DRAW_AND_READBACK
:
668 case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION
:
669 client_
->ScheduledActionBeginOutputSurfaceCreation();
671 case SchedulerStateMachine::ACTION_MANAGE_TILES
:
672 client_
->ScheduledActionManageTiles();
675 } while (action
!= SchedulerStateMachine::ACTION_NONE
);
677 SetupNextBeginFrameIfNeeded();
678 client_
->DidAnticipatedDrawTimeChange(AnticipatedDrawTime());
680 if (state_machine_
.ShouldTriggerBeginImplFrameDeadlineEarly()) {
681 DCHECK(!settings_
.using_synchronous_renderer_compositor
);
682 ScheduleBeginImplFrameDeadline(base::TimeTicks());
686 bool Scheduler::WillDrawIfNeeded() const {
687 return !state_machine_
.PendingDrawsShouldBeAborted();
690 scoped_ptr
<base::Value
> Scheduler::StateAsValue() const {
691 scoped_ptr
<base::DictionaryValue
> state(new base::DictionaryValue
);
692 state
->Set("state_machine", state_machine_
.AsValue().release());
694 scoped_ptr
<base::DictionaryValue
> scheduler_state(new base::DictionaryValue
);
695 scheduler_state
->SetDouble(
696 "time_until_anticipated_draw_time_ms",
697 (AnticipatedDrawTime() - base::TimeTicks::Now()).InMillisecondsF());
698 scheduler_state
->SetDouble("vsync_interval_ms",
699 vsync_interval_
.InMillisecondsF());
700 scheduler_state
->SetDouble("estimated_parent_draw_time_ms",
701 estimated_parent_draw_time_
.InMillisecondsF());
702 scheduler_state
->SetBoolean("last_set_needs_begin_frame_",
703 last_set_needs_begin_frame_
);
704 scheduler_state
->SetBoolean("begin_unthrottled_frame_posted_",
705 begin_unthrottled_frame_posted_
);
706 scheduler_state
->SetBoolean("begin_retro_frame_posted_",
707 begin_retro_frame_posted_
);
708 scheduler_state
->SetInteger("begin_retro_frame_args_",
709 begin_retro_frame_args_
.size());
710 scheduler_state
->SetBoolean("begin_impl_frame_deadline_task_",
711 !begin_impl_frame_deadline_task_
.IsCancelled());
712 scheduler_state
->SetBoolean("poll_for_draw_triggers_task_",
713 !poll_for_draw_triggers_task_
.IsCancelled());
714 scheduler_state
->SetBoolean("advance_commit_state_task_",
715 !advance_commit_state_task_
.IsCancelled());
716 state
->Set("scheduler_state", scheduler_state
.release());
718 scoped_ptr
<base::DictionaryValue
> client_state(new base::DictionaryValue
);
719 client_state
->SetDouble("draw_duration_estimate_ms",
720 client_
->DrawDurationEstimate().InMillisecondsF());
721 client_state
->SetDouble(
722 "begin_main_frame_to_commit_duration_estimate_ms",
723 client_
->BeginMainFrameToCommitDurationEstimate().InMillisecondsF());
724 client_state
->SetDouble(
725 "commit_to_activate_duration_estimate_ms",
726 client_
->CommitToActivateDurationEstimate().InMillisecondsF());
727 state
->Set("client_state", client_state
.release());
728 return state
.PassAs
<base::Value
>();
731 bool Scheduler::CanCommitAndActivateBeforeDeadline() const {
732 // Check if the main thread computation and commit can be finished before the
733 // impl thread's deadline.
734 base::TimeTicks estimated_draw_time
=
735 begin_impl_frame_args_
.frame_time
+
736 client_
->BeginMainFrameToCommitDurationEstimate() +
737 client_
->CommitToActivateDurationEstimate();
740 TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
741 "CanCommitAndActivateBeforeDeadline",
742 "time_left_after_drawing_ms",
743 (begin_impl_frame_args_
.deadline
- estimated_draw_time
).InMillisecondsF(),
745 TracedValue::FromValue(StateAsValue().release()));
747 return estimated_draw_time
< begin_impl_frame_args_
.deadline
;
750 bool Scheduler::IsBeginMainFrameSentOrStarted() const {
751 return (state_machine_
.commit_state() ==
752 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT
||
753 state_machine_
.commit_state() ==
754 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED
);