[NaCl SDK]: use standard __BEGIN_DECLS macros in sys/select.h
[chromium-blink-merge.git] / cc / scheduler / scheduler.cc
blob65f63fc8b641040ad3e26a8e572ae97fd9c6943f
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 base::SingleThreadTaskRunner* task_runner)
23 : scheduler_(scheduler) {
24 if (gfx::FrameTime::TimestampsAreHighRes()) {
25 time_source_ = DelayBasedTimeSourceHighRes::Create(
26 scheduler_->VSyncInterval(), task_runner);
27 } else {
28 time_source_ = DelayBasedTimeSource::Create(scheduler_->VSyncInterval(),
29 task_runner);
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);
70 BeginFrameArgs
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());
78 Scheduler::Scheduler(
79 SchedulerClient* client,
80 const SchedulerSettings& scheduler_settings,
81 int layer_tree_host_id,
82 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
83 : settings_(scheduler_settings),
84 client_(client),
85 layer_tree_host_id_(layer_tree_host_id),
86 task_runner_(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),
94 weak_factory_(this) {
95 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
96 "Scheduler::Scheduler",
97 "settings",
98 settings_.AsValue());
99 DCHECK(client_);
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, 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::SetImplLatencyTakesPriority(bool impl_latency_takes_priority) {
215 state_machine_.SetImplLatencyTakesPriority(impl_latency_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 if (!task_runner_.get())
278 return;
280 bool needs_begin_frame = state_machine_.BeginFrameNeeded();
282 if (settings_.throttle_frame_production) {
283 SetupNextBeginFrameWhenVSyncThrottlingEnabled(needs_begin_frame);
284 } else {
285 SetupNextBeginFrameWhenVSyncThrottlingDisabled(needs_begin_frame);
287 SetupPollingMechanisms(needs_begin_frame);
290 // When we are throttling frame production, we request BeginFrames
291 // from the OutputSurface.
292 void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingEnabled(
293 bool needs_begin_frame) {
294 bool at_end_of_deadline =
295 state_machine_.begin_impl_frame_state() ==
296 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE;
298 bool should_call_set_needs_begin_frame =
299 // Always request the BeginFrame immediately if it wasn't needed before.
300 (needs_begin_frame && !last_set_needs_begin_frame_) ||
301 // Only stop requesting BeginFrames after a deadline.
302 (!needs_begin_frame && last_set_needs_begin_frame_ && at_end_of_deadline);
304 if (should_call_set_needs_begin_frame) {
305 if (settings_.begin_frame_scheduling_enabled) {
306 client_->SetNeedsBeginFrame(needs_begin_frame);
307 } else {
308 synthetic_begin_frame_source_->SetNeedsBeginFrame(
309 needs_begin_frame, &begin_retro_frame_args_);
311 last_set_needs_begin_frame_ = needs_begin_frame;
314 PostBeginRetroFrameIfNeeded();
317 // When we aren't throttling frame production, we initiate a BeginFrame
318 // as soon as one is needed.
319 void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingDisabled(
320 bool needs_begin_frame) {
321 last_set_needs_begin_frame_ = needs_begin_frame;
323 if (!needs_begin_frame || begin_unthrottled_frame_posted_)
324 return;
326 if (state_machine_.begin_impl_frame_state() !=
327 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE &&
328 state_machine_.begin_impl_frame_state() !=
329 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) {
330 return;
333 begin_unthrottled_frame_posted_ = true;
334 task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_);
337 // BeginUnthrottledFrame is used when we aren't throttling frame production.
338 // This will usually be because VSync is disabled.
339 void Scheduler::BeginUnthrottledFrame() {
340 DCHECK(!settings_.throttle_frame_production);
341 DCHECK(begin_retro_frame_args_.empty());
343 base::TimeTicks now = gfx::FrameTime::Now();
344 base::TimeTicks deadline = now + vsync_interval_;
346 BeginFrameArgs begin_frame_args =
347 BeginFrameArgs::Create(now, deadline, vsync_interval_);
348 BeginImplFrame(begin_frame_args);
350 begin_unthrottled_frame_posted_ = false;
353 // We may need to poll when we can't rely on BeginFrame to advance certain
354 // state or to avoid deadlock.
355 void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) {
356 bool needs_advance_commit_state_timer = false;
357 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but
358 // aren't expecting any more BeginFrames. This should only be needed by
359 // the synchronous compositor when BeginFrameNeeded is false.
360 if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) {
361 DCHECK(!state_machine_.SupportsProactiveBeginFrame());
362 DCHECK(!needs_begin_frame);
363 if (poll_for_draw_triggers_task_.IsCancelled()) {
364 poll_for_draw_triggers_task_.Reset(poll_for_draw_triggers_closure_);
365 base::TimeDelta delay = begin_impl_frame_args_.IsValid()
366 ? begin_impl_frame_args_.interval
367 : BeginFrameArgs::DefaultInterval();
368 task_runner_->PostDelayedTask(
369 FROM_HERE, poll_for_draw_triggers_task_.callback(), delay);
371 } else {
372 poll_for_draw_triggers_task_.Cancel();
374 // At this point we'd prefer to advance through the commit flow by
375 // drawing a frame, however it's possible that the frame rate controller
376 // will not give us a BeginFrame until the commit completes. See
377 // crbug.com/317430 for an example of a swap ack being held on commit. Thus
378 // we set a repeating timer to poll on ProcessScheduledActions until we
379 // successfully reach BeginFrame. Synchronous compositor does not use
380 // frame rate controller or have the circular wait in the bug.
381 if (IsBeginMainFrameSentOrStarted() &&
382 !settings_.using_synchronous_renderer_compositor) {
383 needs_advance_commit_state_timer = true;
387 if (needs_advance_commit_state_timer) {
388 if (advance_commit_state_task_.IsCancelled() &&
389 begin_impl_frame_args_.IsValid()) {
390 // Since we'd rather get a BeginImplFrame by the normal mechanism, we
391 // set the interval to twice the interval from the previous frame.
392 advance_commit_state_task_.Reset(advance_commit_state_closure_);
393 task_runner_->PostDelayedTask(FROM_HERE,
394 advance_commit_state_task_.callback(),
395 begin_impl_frame_args_.interval * 2);
397 } else {
398 advance_commit_state_task_.Cancel();
402 // BeginFrame is the mechanism that tells us that now is a good time to start
403 // making a frame. Usually this means that user input for the frame is complete.
404 // If the scheduler is busy, we queue the BeginFrame to be handled later as
405 // a BeginRetroFrame.
406 void Scheduler::BeginFrame(const BeginFrameArgs& args) {
407 TRACE_EVENT1("cc", "Scheduler::BeginFrame", "args", args.AsValue());
408 DCHECK(settings_.throttle_frame_production);
410 BeginFrameArgs adjusted_args(args);
411 adjusted_args.deadline -= EstimatedParentDrawTime();
413 bool should_defer_begin_frame;
414 if (settings_.using_synchronous_renderer_compositor) {
415 should_defer_begin_frame = false;
416 } else {
417 should_defer_begin_frame =
418 !begin_retro_frame_args_.empty() || begin_retro_frame_posted_ ||
419 !last_set_needs_begin_frame_ ||
420 (state_machine_.begin_impl_frame_state() !=
421 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
424 if (should_defer_begin_frame) {
425 begin_retro_frame_args_.push_back(adjusted_args);
426 TRACE_EVENT_INSTANT0(
427 "cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD);
428 return;
431 BeginImplFrame(adjusted_args);
434 // BeginRetroFrame is called for BeginFrames that we've deferred because
435 // the scheduler was in the middle of processing a previous BeginFrame.
436 void Scheduler::BeginRetroFrame() {
437 TRACE_EVENT0("cc", "Scheduler::BeginRetroFrame");
438 DCHECK(!settings_.using_synchronous_renderer_compositor);
439 DCHECK(begin_retro_frame_posted_);
440 begin_retro_frame_posted_ = false;
442 // If there aren't any retroactive BeginFrames, then we've lost the
443 // OutputSurface and should abort.
444 if (begin_retro_frame_args_.empty())
445 return;
447 // Discard expired BeginRetroFrames
448 // Today, we should always end up with at most one un-expired BeginRetroFrame
449 // because deadlines will not be greater than the next frame time. We don't
450 // DCHECK though because some systems don't always have monotonic timestamps.
451 // TODO(brianderson): In the future, long deadlines could result in us not
452 // draining the queue if we don't catch up. If we consistently can't catch
453 // up, our fallback should be to lower our frame rate.
454 base::TimeTicks now = gfx::FrameTime::Now();
455 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate();
456 while (!begin_retro_frame_args_.empty() &&
457 now > AdjustedBeginImplFrameDeadline(begin_retro_frame_args_.front(),
458 draw_duration_estimate)) {
459 TRACE_EVENT1("cc",
460 "Scheduler::BeginRetroFrame discarding",
461 "frame_time",
462 begin_retro_frame_args_.front().frame_time);
463 begin_retro_frame_args_.pop_front();
466 if (begin_retro_frame_args_.empty()) {
467 DCHECK(settings_.throttle_frame_production);
468 TRACE_EVENT_INSTANT0("cc",
469 "Scheduler::BeginRetroFrames all expired",
470 TRACE_EVENT_SCOPE_THREAD);
471 } else {
472 BeginImplFrame(begin_retro_frame_args_.front());
473 begin_retro_frame_args_.pop_front();
477 // There could be a race between the posted BeginRetroFrame and a new
478 // BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame
479 // will check if there is a pending BeginRetroFrame to ensure we handle
480 // BeginFrames in FIFO order.
481 void Scheduler::PostBeginRetroFrameIfNeeded() {
482 if (!last_set_needs_begin_frame_)
483 return;
485 if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_)
486 return;
488 // begin_retro_frame_args_ should always be empty for the
489 // synchronous compositor.
490 DCHECK(!settings_.using_synchronous_renderer_compositor);
492 if (state_machine_.begin_impl_frame_state() !=
493 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE)
494 return;
496 begin_retro_frame_posted_ = true;
497 task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_);
500 // BeginImplFrame starts a compositor frame that will wait up until a deadline
501 // for a BeginMainFrame+activation to complete before it times out and draws
502 // any asynchronous animation and scroll/pinch updates.
503 void Scheduler::BeginImplFrame(const BeginFrameArgs& args) {
504 TRACE_EVENT1("cc", "Scheduler::BeginImplFrame", "args", args.AsValue());
505 DCHECK_EQ(state_machine_.begin_impl_frame_state(),
506 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
507 DCHECK(state_machine_.HasInitializedOutputSurface());
509 advance_commit_state_task_.Cancel();
511 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate();
512 begin_impl_frame_args_ = args;
513 begin_impl_frame_args_.deadline -= draw_duration_estimate;
515 if (!state_machine_.impl_latency_takes_priority() &&
516 state_machine_.MainThreadIsInHighLatencyMode() &&
517 CanCommitAndActivateBeforeDeadline()) {
518 state_machine_.SetSkipNextBeginMainFrameToReduceLatency();
521 client_->WillBeginImplFrame(begin_impl_frame_args_);
522 state_machine_.OnBeginImplFrame(begin_impl_frame_args_);
523 devtools_instrumentation::DidBeginFrame(layer_tree_host_id_);
525 ProcessScheduledActions();
527 state_machine_.OnBeginImplFrameDeadlinePending();
528 ScheduleBeginImplFrameDeadline(
529 AdjustedBeginImplFrameDeadline(args, draw_duration_estimate));
532 base::TimeTicks Scheduler::AdjustedBeginImplFrameDeadline(
533 const BeginFrameArgs& args,
534 base::TimeDelta draw_duration_estimate) const {
535 if (settings_.using_synchronous_renderer_compositor) {
536 // The synchronous compositor needs to draw right away.
537 return base::TimeTicks();
538 } else if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
539 // We are ready to draw a new active tree immediately.
540 return base::TimeTicks();
541 } else if (state_machine_.needs_redraw()) {
542 // We have an animation or fast input path on the impl thread that wants
543 // to draw, so don't wait too long for a new active tree.
544 return args.deadline - draw_duration_estimate;
545 } else {
546 // The impl thread doesn't have anything it wants to draw and we are just
547 // waiting for a new active tree, so post the deadline for the next
548 // expected BeginImplFrame start. This allows us to draw immediately when
549 // there is a new active tree, instead of waiting for the next
550 // BeginImplFrame.
551 // TODO(brianderson): Handle long deadlines (that are past the next frame's
552 // frame time) properly instead of using this hack.
553 return args.frame_time + args.interval;
557 void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) {
558 if (settings_.using_synchronous_renderer_compositor) {
559 // The synchronous renderer compositor has to make its GL calls
560 // within this call.
561 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks
562 // so the sychronous renderer compositor can take advantage of splitting
563 // up the BeginImplFrame and deadline as well.
564 OnBeginImplFrameDeadline();
565 return;
567 begin_impl_frame_deadline_task_.Cancel();
568 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_);
570 base::TimeDelta delta = deadline - gfx::FrameTime::Now();
571 if (delta <= base::TimeDelta())
572 delta = base::TimeDelta();
573 task_runner_->PostDelayedTask(
574 FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta);
577 void Scheduler::OnBeginImplFrameDeadline() {
578 TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline");
579 begin_impl_frame_deadline_task_.Cancel();
581 // We split the deadline actions up into two phases so the state machine
582 // has a chance to trigger actions that should occur durring and after
583 // the deadline separately. For example:
584 // * Sending the BeginMainFrame will not occur after the deadline in
585 // order to wait for more user-input before starting the next commit.
586 // * Creating a new OuputSurface will not occur during the deadline in
587 // order to allow the state machine to "settle" first.
588 state_machine_.OnBeginImplFrameDeadline();
589 ProcessScheduledActions();
590 state_machine_.OnBeginImplFrameIdle();
591 ProcessScheduledActions();
593 client_->DidBeginImplFrameDeadline();
596 void Scheduler::PollForAnticipatedDrawTriggers() {
597 TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers");
598 poll_for_draw_triggers_task_.Cancel();
599 state_machine_.DidEnterPollForAnticipatedDrawTriggers();
600 ProcessScheduledActions();
601 state_machine_.DidLeavePollForAnticipatedDrawTriggers();
604 void Scheduler::PollToAdvanceCommitState() {
605 TRACE_EVENT0("cc", "Scheduler::PollToAdvanceCommitState");
606 advance_commit_state_task_.Cancel();
607 ProcessScheduledActions();
610 void Scheduler::DrawAndSwapIfPossible() {
611 DrawResult result = client_->ScheduledActionDrawAndSwapIfPossible();
612 state_machine_.DidDrawIfPossibleCompleted(result);
615 void Scheduler::ProcessScheduledActions() {
616 // We do not allow ProcessScheduledActions to be recursive.
617 // The top-level call will iteratively execute the next action for us anyway.
618 if (inside_process_scheduled_actions_)
619 return;
621 base::AutoReset<bool> mark_inside(&inside_process_scheduled_actions_, true);
623 SchedulerStateMachine::Action action;
624 do {
625 action = state_machine_.NextAction();
626 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
627 "SchedulerStateMachine",
628 "state",
629 AsValue());
630 VLOG(2) << "Scheduler::ProcessScheduledActions: "
631 << SchedulerStateMachine::ActionToString(action) << " "
632 << state_machine_.GetStatesForDebugging();
633 state_machine_.UpdateState(action);
634 base::AutoReset<SchedulerStateMachine::Action>
635 mark_inside_action(&inside_action_, action);
636 switch (action) {
637 case SchedulerStateMachine::ACTION_NONE:
638 break;
639 case SchedulerStateMachine::ACTION_ANIMATE:
640 client_->ScheduledActionAnimate();
641 break;
642 case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME:
643 client_->ScheduledActionSendBeginMainFrame();
644 break;
645 case SchedulerStateMachine::ACTION_COMMIT:
646 client_->ScheduledActionCommit();
647 break;
648 case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES:
649 client_->ScheduledActionUpdateVisibleTiles();
650 break;
651 case SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE:
652 client_->ScheduledActionActivateSyncTree();
653 break;
654 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
655 DrawAndSwapIfPossible();
656 break;
657 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED:
658 client_->ScheduledActionDrawAndSwapForced();
659 break;
660 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT:
661 // No action is actually performed, but this allows the state machine to
662 // advance out of its waiting to draw state without actually drawing.
663 break;
664 case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
665 client_->ScheduledActionBeginOutputSurfaceCreation();
666 break;
667 case SchedulerStateMachine::ACTION_MANAGE_TILES:
668 client_->ScheduledActionManageTiles();
669 break;
671 } while (action != SchedulerStateMachine::ACTION_NONE);
673 SetupNextBeginFrameIfNeeded();
674 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime());
676 if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
677 DCHECK(!settings_.using_synchronous_renderer_compositor);
678 ScheduleBeginImplFrameDeadline(base::TimeTicks());
682 bool Scheduler::WillDrawIfNeeded() const {
683 return !state_machine_.PendingDrawsShouldBeAborted();
686 scoped_refptr<base::debug::ConvertableToTraceFormat> Scheduler::AsValue()
687 const {
688 scoped_refptr<base::debug::TracedValue> state =
689 new base::debug::TracedValue();
690 state->BeginDictionary("state_machine");
691 state_machine_.AsValueInto(state.get());
692 state->EndDictionary();
693 if (synthetic_begin_frame_source_) {
694 state->BeginDictionary("synthetic_begin_frame_source_");
695 synthetic_begin_frame_source_->AsValueInto(state.get());
696 state->EndDictionary();
699 state->BeginDictionary("scheduler_state");
700 state->SetDouble(
701 "time_until_anticipated_draw_time_ms",
702 (AnticipatedDrawTime() - base::TimeTicks::Now()).InMillisecondsF());
703 state->SetDouble("vsync_interval_ms", vsync_interval_.InMillisecondsF());
704 state->SetDouble("estimated_parent_draw_time_ms",
705 estimated_parent_draw_time_.InMillisecondsF());
706 state->SetBoolean("last_set_needs_begin_frame_", last_set_needs_begin_frame_);
707 state->SetBoolean("begin_unthrottled_frame_posted_",
708 begin_unthrottled_frame_posted_);
709 state->SetBoolean("begin_retro_frame_posted_", begin_retro_frame_posted_);
710 state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size());
711 state->SetBoolean("begin_impl_frame_deadline_task_",
712 !begin_impl_frame_deadline_task_.IsCancelled());
713 state->SetBoolean("poll_for_draw_triggers_task_",
714 !poll_for_draw_triggers_task_.IsCancelled());
715 state->SetBoolean("advance_commit_state_task_",
716 !advance_commit_state_task_.IsCancelled());
717 state->BeginDictionary("begin_impl_frame_args");
718 begin_impl_frame_args_.AsValueInto(state.get());
719 state->EndDictionary();
721 state->EndDictionary();
723 state->BeginDictionary("client_state");
724 state->SetDouble("draw_duration_estimate_ms",
725 client_->DrawDurationEstimate().InMillisecondsF());
726 state->SetDouble(
727 "begin_main_frame_to_commit_duration_estimate_ms",
728 client_->BeginMainFrameToCommitDurationEstimate().InMillisecondsF());
729 state->SetDouble(
730 "commit_to_activate_duration_estimate_ms",
731 client_->CommitToActivateDurationEstimate().InMillisecondsF());
732 state->EndDictionary();
733 return state;
736 bool Scheduler::CanCommitAndActivateBeforeDeadline() const {
737 // Check if the main thread computation and commit can be finished before the
738 // impl thread's deadline.
739 base::TimeTicks estimated_draw_time =
740 begin_impl_frame_args_.frame_time +
741 client_->BeginMainFrameToCommitDurationEstimate() +
742 client_->CommitToActivateDurationEstimate();
744 TRACE_EVENT2(
745 TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
746 "CanCommitAndActivateBeforeDeadline",
747 "time_left_after_drawing_ms",
748 (begin_impl_frame_args_.deadline - estimated_draw_time).InMillisecondsF(),
749 "state",
750 AsValue());
752 return estimated_draw_time < begin_impl_frame_args_.deadline;
755 bool Scheduler::IsBeginMainFrameSentOrStarted() const {
756 return (state_machine_.commit_state() ==
757 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT ||
758 state_machine_.commit_state() ==
759 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED);
762 } // namespace cc