Enables using the magnification API for screen capturing on Windows under a Finch...
[chromium-blink-merge.git] / cc / scheduler / scheduler.cc
blob88c8c74f701d2f4aa0a8980cff8b01f2a21335ea
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/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"
16 namespace cc {
18 class SyntheticBeginFrameSource : public TimeSourceClient {
19 public:
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);
26 } else {
27 time_source_ = DelayBasedTimeSource::Create(scheduler_->VSyncInterval(),
28 task_runner);
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);
60 private:
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_;
72 Scheduler::Scheduler(
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),
78 client_(client),
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),
88 weak_factory_(this) {
89 DCHECK(client_);
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);
274 } else {
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);
297 } else {
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_)
314 return;
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) {
320 return;
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);
361 } else {
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);
387 } else {
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;
403 } else {
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);
415 return;
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())
432 return;
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)) {
446 TRACE_EVENT1("cc",
447 "Scheduler::BeginRetroFrame discarding",
448 "frame_time",
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);
458 } else {
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_)
470 return;
472 if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_)
473 return;
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)
481 return;
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) {
491 TRACE_EVENT1(
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;
533 } else {
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
538 // BeginImplFrame.
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
548 // within this call.
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();
553 return;
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_)
622 return;
624 base::AutoReset<bool> mark_inside(&inside_process_scheduled_actions_, true);
626 SchedulerStateMachine::Action action;
627 do {
628 state_machine_.CheckInvariants();
629 action = state_machine_.NextAction();
630 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
631 "SchedulerStateMachine",
632 "state",
633 TracedValue::FromValue(StateAsValue().release()));
634 state_machine_.UpdateState(action);
635 base::AutoReset<SchedulerStateMachine::Action>
636 mark_inside_action(&inside_action_, action);
637 switch (action) {
638 case SchedulerStateMachine::ACTION_NONE:
639 break;
640 case SchedulerStateMachine::ACTION_ANIMATE:
641 client_->ScheduledActionAnimate();
642 break;
643 case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME:
644 client_->ScheduledActionSendBeginMainFrame();
645 break;
646 case SchedulerStateMachine::ACTION_COMMIT:
647 client_->ScheduledActionCommit();
648 break;
649 case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES:
650 client_->ScheduledActionUpdateVisibleTiles();
651 break;
652 case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE:
653 ActivatePendingTree();
654 break;
655 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
656 DrawAndSwapIfPossible();
657 break;
658 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED:
659 DrawAndSwapForced();
660 break;
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.
664 break;
665 case SchedulerStateMachine::ACTION_DRAW_AND_READBACK:
666 DrawAndReadback();
667 break;
668 case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
669 client_->ScheduledActionBeginOutputSurfaceCreation();
670 break;
671 case SchedulerStateMachine::ACTION_MANAGE_TILES:
672 client_->ScheduledActionManageTiles();
673 break;
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();
739 TRACE_EVENT2(
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(),
744 "state",
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);
757 } // namespace cc