Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(767)

Side by Side Diff: cc/scheduler/scheduler.cc

Issue 1533773002: Delete CC. (Closed) Base URL: git@github.com:domokit/mojo.git@cl-2e
Patch Set: rebase Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « cc/scheduler/scheduler.h ('k') | cc/scheduler/scheduler_settings.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "cc/scheduler/scheduler.h"
6
7 #include <algorithm>
8
9 #include "base/auto_reset.h"
10 #include "base/logging.h"
11 #include "base/profiler/scoped_tracker.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/trace_event/trace_event.h"
14 #include "base/trace_event/trace_event_argument.h"
15 #include "cc/debug/traced_value.h"
16 #include "cc/scheduler/delay_based_time_source.h"
17 #include "ui/gfx/frame_time.h"
18
19 namespace cc {
20
21 BeginFrameSource* SchedulerFrameSourcesConstructor::ConstructPrimaryFrameSource(
22 Scheduler* scheduler) {
23 if (scheduler->settings_.use_external_begin_frame_source) {
24 TRACE_EVENT1("cc",
25 "Scheduler::Scheduler()",
26 "PrimaryFrameSource",
27 "ExternalBeginFrameSource");
28 DCHECK(scheduler->primary_frame_source_internal_)
29 << "Need external BeginFrameSource";
30 return scheduler->primary_frame_source_internal_.get();
31 } else {
32 TRACE_EVENT1("cc",
33 "Scheduler::Scheduler()",
34 "PrimaryFrameSource",
35 "SyntheticBeginFrameSource");
36 scoped_ptr<SyntheticBeginFrameSource> synthetic_source =
37 SyntheticBeginFrameSource::Create(scheduler->task_runner_.get(),
38 scheduler->Now(),
39 BeginFrameArgs::DefaultInterval());
40
41 DCHECK(!scheduler->vsync_observer_);
42 scheduler->vsync_observer_ = synthetic_source.get();
43
44 DCHECK(!scheduler->primary_frame_source_internal_);
45 scheduler->primary_frame_source_internal_ = synthetic_source.Pass();
46 return scheduler->primary_frame_source_internal_.get();
47 }
48 }
49
50 BeginFrameSource*
51 SchedulerFrameSourcesConstructor::ConstructBackgroundFrameSource(
52 Scheduler* scheduler) {
53 TRACE_EVENT1("cc",
54 "Scheduler::Scheduler()",
55 "BackgroundFrameSource",
56 "SyntheticBeginFrameSource");
57 DCHECK(!(scheduler->background_frame_source_internal_));
58 scheduler->background_frame_source_internal_ =
59 SyntheticBeginFrameSource::Create(
60 scheduler->task_runner_.get(), scheduler->Now(),
61 scheduler->settings_.background_frame_interval);
62 return scheduler->background_frame_source_internal_.get();
63 }
64
65 BeginFrameSource*
66 SchedulerFrameSourcesConstructor::ConstructUnthrottledFrameSource(
67 Scheduler* scheduler) {
68 TRACE_EVENT1("cc", "Scheduler::Scheduler()", "UnthrottledFrameSource",
69 "BackToBackBeginFrameSource");
70 DCHECK(!scheduler->unthrottled_frame_source_internal_);
71 scheduler->unthrottled_frame_source_internal_ =
72 BackToBackBeginFrameSource::Create(scheduler->task_runner_.get());
73 return scheduler->unthrottled_frame_source_internal_.get();
74 }
75
76 Scheduler::Scheduler(
77 SchedulerClient* client,
78 const SchedulerSettings& scheduler_settings,
79 int layer_tree_host_id,
80 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
81 scoped_ptr<BeginFrameSource> external_begin_frame_source,
82 SchedulerFrameSourcesConstructor* frame_sources_constructor)
83 : frame_source_(),
84 primary_frame_source_(NULL),
85 background_frame_source_(NULL),
86 primary_frame_source_internal_(external_begin_frame_source.Pass()),
87 background_frame_source_internal_(),
88 vsync_observer_(NULL),
89 throttle_frame_production_(scheduler_settings.throttle_frame_production),
90 settings_(scheduler_settings),
91 client_(client),
92 layer_tree_host_id_(layer_tree_host_id),
93 task_runner_(task_runner),
94 state_machine_(scheduler_settings),
95 inside_process_scheduled_actions_(false),
96 inside_action_(SchedulerStateMachine::ACTION_NONE),
97 weak_factory_(this) {
98 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
99 "Scheduler::Scheduler",
100 "settings",
101 settings_.AsValue());
102 DCHECK(client_);
103 DCHECK(!state_machine_.BeginFrameNeeded());
104
105 begin_retro_frame_closure_ =
106 base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr());
107 begin_impl_frame_deadline_closure_ = base::Bind(
108 &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr());
109 poll_for_draw_triggers_closure_ = base::Bind(
110 &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr());
111 advance_commit_state_closure_ = base::Bind(
112 &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr());
113
114 frame_source_ = BeginFrameSourceMultiplexer::Create();
115 frame_source_->AddObserver(this);
116
117 // Primary frame source
118 primary_frame_source_ =
119 frame_sources_constructor->ConstructPrimaryFrameSource(this);
120 frame_source_->AddSource(primary_frame_source_);
121 primary_frame_source_->SetClientReady();
122
123 // Background ticking frame source
124 background_frame_source_ =
125 frame_sources_constructor->ConstructBackgroundFrameSource(this);
126 frame_source_->AddSource(background_frame_source_);
127
128 // Unthrottled frame source
129 unthrottled_frame_source_ =
130 frame_sources_constructor->ConstructUnthrottledFrameSource(this);
131 frame_source_->AddSource(unthrottled_frame_source_);
132 }
133
134 Scheduler::~Scheduler() {
135 if (frame_source_->NeedsBeginFrames())
136 frame_source_->SetNeedsBeginFrames(false);
137 }
138
139 base::TimeTicks Scheduler::Now() const {
140 base::TimeTicks now = gfx::FrameTime::Now();
141 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.now"),
142 "Scheduler::Now",
143 "now",
144 now);
145 return now;
146 }
147
148 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase,
149 base::TimeDelta interval) {
150 // TODO(brianderson): We should not be receiving 0 intervals.
151 if (interval == base::TimeDelta())
152 interval = BeginFrameArgs::DefaultInterval();
153
154 if (vsync_observer_)
155 vsync_observer_->OnUpdateVSyncParameters(timebase, interval);
156 }
157
158 void Scheduler::SetEstimatedParentDrawTime(base::TimeDelta draw_time) {
159 DCHECK_GE(draw_time.ToInternalValue(), 0);
160 estimated_parent_draw_time_ = draw_time;
161 }
162
163 void Scheduler::SetCanStart() {
164 state_machine_.SetCanStart();
165 ProcessScheduledActions();
166 }
167
168 void Scheduler::UpdateActiveFrameSource() {
169 if (state_machine_.visible()) {
170 if (throttle_frame_production_) {
171 frame_source_->SetActiveSource(primary_frame_source_);
172 } else {
173 frame_source_->SetActiveSource(unthrottled_frame_source_);
174 }
175 } else {
176 frame_source_->SetActiveSource(background_frame_source_);
177 }
178 ProcessScheduledActions();
179 }
180
181 void Scheduler::SetVisible(bool visible) {
182 state_machine_.SetVisible(visible);
183 UpdateActiveFrameSource();
184 }
185
186 void Scheduler::SetCanDraw(bool can_draw) {
187 state_machine_.SetCanDraw(can_draw);
188 ProcessScheduledActions();
189 }
190
191 void Scheduler::NotifyReadyToActivate() {
192 state_machine_.NotifyReadyToActivate();
193 ProcessScheduledActions();
194 }
195
196 void Scheduler::NotifyReadyToDraw() {
197 // Empty for now, until we take action based on the notification as part of
198 // crbugs 352894, 383157, 421923.
199 }
200
201 void Scheduler::SetThrottleFrameProduction(bool throttle) {
202 throttle_frame_production_ = throttle;
203 UpdateActiveFrameSource();
204 }
205
206 void Scheduler::SetNeedsCommit() {
207 state_machine_.SetNeedsCommit();
208 ProcessScheduledActions();
209 }
210
211 void Scheduler::SetNeedsRedraw() {
212 state_machine_.SetNeedsRedraw();
213 ProcessScheduledActions();
214 }
215
216 void Scheduler::SetNeedsAnimate() {
217 state_machine_.SetNeedsAnimate();
218 ProcessScheduledActions();
219 }
220
221 void Scheduler::SetNeedsPrepareTiles() {
222 DCHECK(!IsInsideAction(SchedulerStateMachine::ACTION_PREPARE_TILES));
223 state_machine_.SetNeedsPrepareTiles();
224 ProcessScheduledActions();
225 }
226
227 void Scheduler::SetMaxSwapsPending(int max) {
228 state_machine_.SetMaxSwapsPending(max);
229 }
230
231 void Scheduler::DidSwapBuffers() {
232 state_machine_.DidSwapBuffers();
233
234 // There is no need to call ProcessScheduledActions here because
235 // swapping should not trigger any new actions.
236 if (!inside_process_scheduled_actions_) {
237 DCHECK_EQ(state_machine_.NextAction(), SchedulerStateMachine::ACTION_NONE);
238 }
239 }
240
241 void Scheduler::DidSwapBuffersComplete() {
242 state_machine_.DidSwapBuffersComplete();
243 ProcessScheduledActions();
244 }
245
246 void Scheduler::SetImplLatencyTakesPriority(bool impl_latency_takes_priority) {
247 state_machine_.SetImplLatencyTakesPriority(impl_latency_takes_priority);
248 ProcessScheduledActions();
249 }
250
251 void Scheduler::NotifyReadyToCommit() {
252 TRACE_EVENT0("cc", "Scheduler::NotifyReadyToCommit");
253 state_machine_.NotifyReadyToCommit();
254 ProcessScheduledActions();
255 }
256
257 void Scheduler::BeginMainFrameAborted(CommitEarlyOutReason reason) {
258 TRACE_EVENT1("cc", "Scheduler::BeginMainFrameAborted", "reason",
259 CommitEarlyOutReasonToString(reason));
260 state_machine_.BeginMainFrameAborted(reason);
261 ProcessScheduledActions();
262 }
263
264 void Scheduler::DidPrepareTiles() {
265 state_machine_.DidPrepareTiles();
266 }
267
268 void Scheduler::DidLoseOutputSurface() {
269 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface");
270 begin_retro_frame_args_.clear();
271 begin_retro_frame_task_.Cancel();
272 state_machine_.DidLoseOutputSurface();
273 ProcessScheduledActions();
274 }
275
276 void Scheduler::DidCreateAndInitializeOutputSurface() {
277 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface");
278 DCHECK(!frame_source_->NeedsBeginFrames());
279 DCHECK(begin_impl_frame_deadline_task_.IsCancelled());
280 state_machine_.DidCreateAndInitializeOutputSurface();
281 ProcessScheduledActions();
282 }
283
284 void Scheduler::NotifyBeginMainFrameStarted() {
285 TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted");
286 state_machine_.NotifyBeginMainFrameStarted();
287 }
288
289 base::TimeTicks Scheduler::AnticipatedDrawTime() const {
290 if (!frame_source_->NeedsBeginFrames() ||
291 begin_impl_frame_args_.interval <= base::TimeDelta())
292 return base::TimeTicks();
293
294 base::TimeTicks now = Now();
295 base::TimeTicks timebase = std::max(begin_impl_frame_args_.frame_time,
296 begin_impl_frame_args_.deadline);
297 int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval);
298 return timebase + (begin_impl_frame_args_.interval * intervals);
299 }
300
301 base::TimeTicks Scheduler::LastBeginImplFrameTime() {
302 return begin_impl_frame_args_.frame_time;
303 }
304
305 void Scheduler::SetupNextBeginFrameIfNeeded() {
306 // Never call SetNeedsBeginFrames if the frame source already has the right
307 // value.
308 if (frame_source_->NeedsBeginFrames() != state_machine_.BeginFrameNeeded()) {
309 if (state_machine_.BeginFrameNeeded()) {
310 // Call SetNeedsBeginFrames(true) as soon as possible.
311 frame_source_->SetNeedsBeginFrames(true);
312 } else if (state_machine_.begin_impl_frame_state() ==
313 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE) {
314 // Call SetNeedsBeginFrames(false) in between frames only.
315 frame_source_->SetNeedsBeginFrames(false);
316 client_->SendBeginMainFrameNotExpectedSoon();
317 }
318 }
319
320 PostBeginRetroFrameIfNeeded();
321 }
322
323 // We may need to poll when we can't rely on BeginFrame to advance certain
324 // state or to avoid deadlock.
325 void Scheduler::SetupPollingMechanisms() {
326 bool needs_advance_commit_state_timer = false;
327 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but
328 // aren't expecting any more BeginFrames. This should only be needed by
329 // the synchronous compositor when BeginFrameNeeded is false.
330 if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) {
331 DCHECK(!state_machine_.SupportsProactiveBeginFrame());
332 if (poll_for_draw_triggers_task_.IsCancelled()) {
333 poll_for_draw_triggers_task_.Reset(poll_for_draw_triggers_closure_);
334 base::TimeDelta delay = begin_impl_frame_args_.IsValid()
335 ? begin_impl_frame_args_.interval
336 : BeginFrameArgs::DefaultInterval();
337 task_runner_->PostDelayedTask(
338 FROM_HERE, poll_for_draw_triggers_task_.callback(), delay);
339 }
340 } else {
341 poll_for_draw_triggers_task_.Cancel();
342
343 // At this point we'd prefer to advance through the commit flow by
344 // drawing a frame, however it's possible that the frame rate controller
345 // will not give us a BeginFrame until the commit completes. See
346 // crbug.com/317430 for an example of a swap ack being held on commit. Thus
347 // we set a repeating timer to poll on ProcessScheduledActions until we
348 // successfully reach BeginFrame. Synchronous compositor does not use
349 // frame rate controller or have the circular wait in the bug.
350 if (IsBeginMainFrameSentOrStarted() &&
351 !settings_.using_synchronous_renderer_compositor) {
352 needs_advance_commit_state_timer = true;
353 }
354 }
355
356 if (needs_advance_commit_state_timer) {
357 if (advance_commit_state_task_.IsCancelled() &&
358 begin_impl_frame_args_.IsValid()) {
359 // Since we'd rather get a BeginImplFrame by the normal mechanism, we
360 // set the interval to twice the interval from the previous frame.
361 advance_commit_state_task_.Reset(advance_commit_state_closure_);
362 task_runner_->PostDelayedTask(FROM_HERE,
363 advance_commit_state_task_.callback(),
364 begin_impl_frame_args_.interval * 2);
365 }
366 } else {
367 advance_commit_state_task_.Cancel();
368 }
369 }
370
371 // BeginFrame is the mechanism that tells us that now is a good time to start
372 // making a frame. Usually this means that user input for the frame is complete.
373 // If the scheduler is busy, we queue the BeginFrame to be handled later as
374 // a BeginRetroFrame.
375 bool Scheduler::OnBeginFrameMixInDelegate(const BeginFrameArgs& args) {
376 TRACE_EVENT1("cc,benchmark", "Scheduler::BeginFrame", "args", args.AsValue());
377
378 // Deliver BeginFrames to children.
379 if (state_machine_.children_need_begin_frames()) {
380 BeginFrameArgs adjusted_args_for_children(args);
381 // Adjust a deadline for child schedulers.
382 // TODO(simonhong): Once we have commitless update, we can get rid of
383 // BeginMainFrameToCommitDurationEstimate() +
384 // CommitToActivateDurationEstimate().
385 adjusted_args_for_children.deadline -=
386 (client_->BeginMainFrameToCommitDurationEstimate() +
387 client_->CommitToActivateDurationEstimate() +
388 client_->DrawDurationEstimate() + EstimatedParentDrawTime());
389 client_->SendBeginFramesToChildren(adjusted_args_for_children);
390 }
391
392 // We have just called SetNeedsBeginFrame(true) and the BeginFrameSource has
393 // sent us the last BeginFrame we have missed. As we might not be able to
394 // actually make rendering for this call, handle it like a "retro frame".
395 // TODO(brainderson): Add a test for this functionality ASAP!
396 if (args.type == BeginFrameArgs::MISSED) {
397 begin_retro_frame_args_.push_back(args);
398 PostBeginRetroFrameIfNeeded();
399 return true;
400 }
401
402 BeginFrameArgs adjusted_args(args);
403 adjusted_args.deadline -= EstimatedParentDrawTime();
404
405 bool should_defer_begin_frame;
406 if (settings_.using_synchronous_renderer_compositor) {
407 should_defer_begin_frame = false;
408 } else {
409 should_defer_begin_frame =
410 !begin_retro_frame_args_.empty() ||
411 !begin_retro_frame_task_.IsCancelled() ||
412 !frame_source_->NeedsBeginFrames() ||
413 (state_machine_.begin_impl_frame_state() !=
414 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
415 }
416
417 if (should_defer_begin_frame) {
418 begin_retro_frame_args_.push_back(adjusted_args);
419 TRACE_EVENT_INSTANT0(
420 "cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD);
421 // Queuing the frame counts as "using it", so we need to return true.
422 } else {
423 BeginImplFrame(adjusted_args);
424 }
425 return true;
426 }
427
428 void Scheduler::SetChildrenNeedBeginFrames(bool children_need_begin_frames) {
429 state_machine_.SetChildrenNeedBeginFrames(children_need_begin_frames);
430 ProcessScheduledActions();
431 }
432
433 // BeginRetroFrame is called for BeginFrames that we've deferred because
434 // the scheduler was in the middle of processing a previous BeginFrame.
435 void Scheduler::BeginRetroFrame() {
436 TRACE_EVENT0("cc,benchmark", "Scheduler::BeginRetroFrame");
437 DCHECK(!settings_.using_synchronous_renderer_compositor);
438 DCHECK(!begin_retro_frame_args_.empty());
439 DCHECK(!begin_retro_frame_task_.IsCancelled());
440 DCHECK_EQ(state_machine_.begin_impl_frame_state(),
441 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
442
443 begin_retro_frame_task_.Cancel();
444
445 // Discard expired BeginRetroFrames
446 // Today, we should always end up with at most one un-expired BeginRetroFrame
447 // because deadlines will not be greater than the next frame time. We don't
448 // DCHECK though because some systems don't always have monotonic timestamps.
449 // TODO(brianderson): In the future, long deadlines could result in us not
450 // draining the queue if we don't catch up. If we consistently can't catch
451 // up, our fallback should be to lower our frame rate.
452 base::TimeTicks now = Now();
453
454 while (!begin_retro_frame_args_.empty()) {
455 const BeginFrameArgs& args = begin_retro_frame_args_.front();
456 base::TimeTicks expiration_time = args.frame_time + args.interval;
457 if (now <= expiration_time)
458 break;
459 TRACE_EVENT_INSTANT2(
460 "cc", "Scheduler::BeginRetroFrame discarding", TRACE_EVENT_SCOPE_THREAD,
461 "expiration_time - now", (expiration_time - now).InMillisecondsF(),
462 "BeginFrameArgs", begin_retro_frame_args_.front().AsValue());
463 begin_retro_frame_args_.pop_front();
464 frame_source_->DidFinishFrame(begin_retro_frame_args_.size());
465 }
466
467 if (begin_retro_frame_args_.empty()) {
468 TRACE_EVENT_INSTANT0("cc",
469 "Scheduler::BeginRetroFrames all expired",
470 TRACE_EVENT_SCOPE_THREAD);
471 } else {
472 BeginFrameArgs front = begin_retro_frame_args_.front();
473 begin_retro_frame_args_.pop_front();
474 BeginImplFrame(front);
475 }
476 }
477
478 // There could be a race between the posted BeginRetroFrame and a new
479 // BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame
480 // will check if there is a pending BeginRetroFrame to ensure we handle
481 // BeginFrames in FIFO order.
482 void Scheduler::PostBeginRetroFrameIfNeeded() {
483 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
484 "Scheduler::PostBeginRetroFrameIfNeeded",
485 "state",
486 AsValue());
487 if (!frame_source_->NeedsBeginFrames())
488 return;
489
490 if (begin_retro_frame_args_.empty() || !begin_retro_frame_task_.IsCancelled())
491 return;
492
493 // begin_retro_frame_args_ should always be empty for the
494 // synchronous compositor.
495 DCHECK(!settings_.using_synchronous_renderer_compositor);
496
497 if (state_machine_.begin_impl_frame_state() !=
498 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE)
499 return;
500
501 begin_retro_frame_task_.Reset(begin_retro_frame_closure_);
502
503 task_runner_->PostTask(FROM_HERE, begin_retro_frame_task_.callback());
504 }
505
506 // BeginImplFrame starts a compositor frame that will wait up until a deadline
507 // for a BeginMainFrame+activation to complete before it times out and draws
508 // any asynchronous animation and scroll/pinch updates.
509 void Scheduler::BeginImplFrame(const BeginFrameArgs& args) {
510 bool main_thread_is_in_high_latency_mode =
511 state_machine_.MainThreadIsInHighLatencyMode();
512 TRACE_EVENT2("cc,benchmark",
513 "Scheduler::BeginImplFrame",
514 "args",
515 args.AsValue(),
516 "main_thread_is_high_latency",
517 main_thread_is_in_high_latency_mode);
518 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
519 "MainThreadLatency",
520 main_thread_is_in_high_latency_mode);
521 DCHECK_EQ(state_machine_.begin_impl_frame_state(),
522 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
523 DCHECK(state_machine_.HasInitializedOutputSurface());
524
525 advance_commit_state_task_.Cancel();
526
527 begin_impl_frame_args_ = args;
528 begin_impl_frame_args_.deadline -= client_->DrawDurationEstimate();
529
530 if (!state_machine_.impl_latency_takes_priority() &&
531 main_thread_is_in_high_latency_mode &&
532 CanCommitAndActivateBeforeDeadline()) {
533 state_machine_.SetSkipNextBeginMainFrameToReduceLatency();
534 }
535
536 state_machine_.OnBeginImplFrame();
537 client_->WillBeginImplFrame(begin_impl_frame_args_);
538
539 ProcessScheduledActions();
540
541 state_machine_.OnBeginImplFrameDeadlinePending();
542
543 if (settings_.using_synchronous_renderer_compositor) {
544 // The synchronous renderer compositor has to make its GL calls
545 // within this call.
546 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks
547 // so the synchronous renderer compositor can take advantage of splitting
548 // up the BeginImplFrame and deadline as well.
549 OnBeginImplFrameDeadline();
550 } else {
551 ScheduleBeginImplFrameDeadline();
552 }
553 }
554
555 void Scheduler::ScheduleBeginImplFrameDeadline() {
556 // The synchronous compositor does not post a deadline task.
557 DCHECK(!settings_.using_synchronous_renderer_compositor);
558
559 begin_impl_frame_deadline_task_.Cancel();
560 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_);
561
562 begin_impl_frame_deadline_mode_ =
563 state_machine_.CurrentBeginImplFrameDeadlineMode();
564
565 base::TimeTicks deadline;
566 switch (begin_impl_frame_deadline_mode_) {
567 case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE:
568 // We are ready to draw a new active tree immediately.
569 // We don't use Now() here because it's somewhat expensive to call.
570 deadline = base::TimeTicks();
571 break;
572 case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR:
573 // We are animating on the impl thread but we can wait for some time.
574 deadline = begin_impl_frame_args_.deadline;
575 break;
576 case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE:
577 // We are blocked for one reason or another and we should wait.
578 // TODO(brianderson): Handle long deadlines (that are past the next
579 // frame's frame time) properly instead of using this hack.
580 deadline =
581 begin_impl_frame_args_.frame_time + begin_impl_frame_args_.interval;
582 break;
583 }
584
585 TRACE_EVENT1(
586 "cc", "Scheduler::ScheduleBeginImplFrameDeadline", "deadline", deadline);
587
588 base::TimeDelta delta = deadline - Now();
589 if (delta <= base::TimeDelta())
590 delta = base::TimeDelta();
591 task_runner_->PostDelayedTask(
592 FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta);
593 }
594
595 void Scheduler::RescheduleBeginImplFrameDeadlineIfNeeded() {
596 if (settings_.using_synchronous_renderer_compositor)
597 return;
598
599 if (state_machine_.begin_impl_frame_state() !=
600 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
601 return;
602
603 if (begin_impl_frame_deadline_mode_ !=
604 state_machine_.CurrentBeginImplFrameDeadlineMode())
605 ScheduleBeginImplFrameDeadline();
606 }
607
608 void Scheduler::OnBeginImplFrameDeadline() {
609 TRACE_EVENT0("cc,benchmark", "Scheduler::OnBeginImplFrameDeadline");
610 begin_impl_frame_deadline_task_.Cancel();
611 // We split the deadline actions up into two phases so the state machine
612 // has a chance to trigger actions that should occur durring and after
613 // the deadline separately. For example:
614 // * Sending the BeginMainFrame will not occur after the deadline in
615 // order to wait for more user-input before starting the next commit.
616 // * Creating a new OuputSurface will not occur during the deadline in
617 // order to allow the state machine to "settle" first.
618
619 // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is fixed.
620 tracked_objects::ScopedTracker tracking_profile1(
621 FROM_HERE_WITH_EXPLICIT_FUNCTION(
622 "461509 Scheduler::OnBeginImplFrameDeadline1"));
623 state_machine_.OnBeginImplFrameDeadline();
624 ProcessScheduledActions();
625 state_machine_.OnBeginImplFrameIdle();
626 ProcessScheduledActions();
627
628 client_->DidBeginImplFrameDeadline();
629 frame_source_->DidFinishFrame(begin_retro_frame_args_.size());
630 }
631
632 void Scheduler::PollForAnticipatedDrawTriggers() {
633 TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers");
634 poll_for_draw_triggers_task_.Cancel();
635 state_machine_.DidEnterPollForAnticipatedDrawTriggers();
636 ProcessScheduledActions();
637 state_machine_.DidLeavePollForAnticipatedDrawTriggers();
638 }
639
640 void Scheduler::PollToAdvanceCommitState() {
641 TRACE_EVENT0("cc", "Scheduler::PollToAdvanceCommitState");
642 advance_commit_state_task_.Cancel();
643 ProcessScheduledActions();
644 }
645
646 void Scheduler::DrawAndSwapIfPossible() {
647 DrawResult result = client_->ScheduledActionDrawAndSwapIfPossible();
648 state_machine_.DidDrawIfPossibleCompleted(result);
649 }
650
651 void Scheduler::SetDeferCommits(bool defer_commits) {
652 TRACE_EVENT1("cc", "Scheduler::SetDeferCommits",
653 "defer_commits",
654 defer_commits);
655 state_machine_.SetDeferCommits(defer_commits);
656 ProcessScheduledActions();
657 }
658
659 void Scheduler::ProcessScheduledActions() {
660 // We do not allow ProcessScheduledActions to be recursive.
661 // The top-level call will iteratively execute the next action for us anyway.
662 if (inside_process_scheduled_actions_)
663 return;
664
665 base::AutoReset<bool> mark_inside(&inside_process_scheduled_actions_, true);
666
667 SchedulerStateMachine::Action action;
668 do {
669 action = state_machine_.NextAction();
670 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
671 "SchedulerStateMachine",
672 "state",
673 AsValue());
674 VLOG(2) << "Scheduler::ProcessScheduledActions: "
675 << SchedulerStateMachine::ActionToString(action) << " "
676 << state_machine_.GetStatesForDebugging();
677 state_machine_.UpdateState(action);
678 base::AutoReset<SchedulerStateMachine::Action>
679 mark_inside_action(&inside_action_, action);
680 switch (action) {
681 case SchedulerStateMachine::ACTION_NONE:
682 break;
683 case SchedulerStateMachine::ACTION_ANIMATE:
684 client_->ScheduledActionAnimate();
685 break;
686 case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME:
687 client_->ScheduledActionSendBeginMainFrame();
688 break;
689 case SchedulerStateMachine::ACTION_COMMIT: {
690 // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is
691 // fixed.
692 tracked_objects::ScopedTracker tracking_profile4(
693 FROM_HERE_WITH_EXPLICIT_FUNCTION(
694 "461509 Scheduler::ProcessScheduledActions4"));
695 client_->ScheduledActionCommit();
696 break;
697 }
698 case SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE:
699 client_->ScheduledActionActivateSyncTree();
700 break;
701 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: {
702 // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is
703 // fixed.
704 tracked_objects::ScopedTracker tracking_profile6(
705 FROM_HERE_WITH_EXPLICIT_FUNCTION(
706 "461509 Scheduler::ProcessScheduledActions6"));
707 DrawAndSwapIfPossible();
708 break;
709 }
710 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED:
711 client_->ScheduledActionDrawAndSwapForced();
712 break;
713 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT:
714 // No action is actually performed, but this allows the state machine to
715 // advance out of its waiting to draw state without actually drawing.
716 break;
717 case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
718 client_->ScheduledActionBeginOutputSurfaceCreation();
719 break;
720 case SchedulerStateMachine::ACTION_PREPARE_TILES:
721 client_->ScheduledActionPrepareTiles();
722 break;
723 }
724 } while (action != SchedulerStateMachine::ACTION_NONE);
725
726 SetupPollingMechanisms();
727
728 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime());
729
730 RescheduleBeginImplFrameDeadlineIfNeeded();
731
732 SetupNextBeginFrameIfNeeded();
733 }
734
735 scoped_refptr<base::trace_event::ConvertableToTraceFormat> Scheduler::AsValue()
736 const {
737 scoped_refptr<base::trace_event::TracedValue> state =
738 new base::trace_event::TracedValue();
739 AsValueInto(state.get());
740 return state;
741 }
742
743 void Scheduler::AsValueInto(base::trace_event::TracedValue* state) const {
744 state->BeginDictionary("state_machine");
745 state_machine_.AsValueInto(state);
746 state->EndDictionary();
747
748 // Only trace frame sources when explicitly enabled - http://crbug.com/420607
749 bool frame_tracing_enabled = false;
750 TRACE_EVENT_CATEGORY_GROUP_ENABLED(
751 TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"),
752 &frame_tracing_enabled);
753 if (frame_tracing_enabled) {
754 state->BeginDictionary("frame_source_");
755 frame_source_->AsValueInto(state);
756 state->EndDictionary();
757 }
758
759 state->BeginDictionary("scheduler_state");
760 state->SetDouble("time_until_anticipated_draw_time_ms",
761 (AnticipatedDrawTime() - Now()).InMillisecondsF());
762 state->SetDouble("estimated_parent_draw_time_ms",
763 estimated_parent_draw_time_.InMillisecondsF());
764 state->SetBoolean("last_set_needs_begin_frame_",
765 frame_source_->NeedsBeginFrames());
766 state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size());
767 state->SetBoolean("begin_retro_frame_task_",
768 !begin_retro_frame_task_.IsCancelled());
769 state->SetBoolean("begin_impl_frame_deadline_task_",
770 !begin_impl_frame_deadline_task_.IsCancelled());
771 state->SetBoolean("poll_for_draw_triggers_task_",
772 !poll_for_draw_triggers_task_.IsCancelled());
773 state->SetBoolean("advance_commit_state_task_",
774 !advance_commit_state_task_.IsCancelled());
775 state->BeginDictionary("begin_impl_frame_args");
776 begin_impl_frame_args_.AsValueInto(state);
777 state->EndDictionary();
778
779 base::TimeTicks now = Now();
780 base::TimeTicks frame_time = begin_impl_frame_args_.frame_time;
781 base::TimeTicks deadline = begin_impl_frame_args_.deadline;
782 base::TimeDelta interval = begin_impl_frame_args_.interval;
783 state->BeginDictionary("major_timestamps_in_ms");
784 state->SetDouble("0_interval", interval.InMillisecondsF());
785 state->SetDouble("1_now_to_deadline", (deadline - now).InMillisecondsF());
786 state->SetDouble("2_frame_time_to_now", (now - frame_time).InMillisecondsF());
787 state->SetDouble("3_frame_time_to_deadline",
788 (deadline - frame_time).InMillisecondsF());
789 state->SetDouble("4_now", (now - base::TimeTicks()).InMillisecondsF());
790 state->SetDouble("5_frame_time",
791 (frame_time - base::TimeTicks()).InMillisecondsF());
792 state->SetDouble("6_deadline",
793 (deadline - base::TimeTicks()).InMillisecondsF());
794 state->EndDictionary();
795
796 state->EndDictionary();
797
798 state->BeginDictionary("client_state");
799 state->SetDouble("draw_duration_estimate_ms",
800 client_->DrawDurationEstimate().InMillisecondsF());
801 state->SetDouble(
802 "begin_main_frame_to_commit_duration_estimate_ms",
803 client_->BeginMainFrameToCommitDurationEstimate().InMillisecondsF());
804 state->SetDouble(
805 "commit_to_activate_duration_estimate_ms",
806 client_->CommitToActivateDurationEstimate().InMillisecondsF());
807 state->EndDictionary();
808 }
809
810 bool Scheduler::CanCommitAndActivateBeforeDeadline() const {
811 // Check if the main thread computation and commit can be finished before the
812 // impl thread's deadline.
813 base::TimeTicks estimated_draw_time =
814 begin_impl_frame_args_.frame_time +
815 client_->BeginMainFrameToCommitDurationEstimate() +
816 client_->CommitToActivateDurationEstimate();
817
818 TRACE_EVENT2(
819 TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
820 "CanCommitAndActivateBeforeDeadline",
821 "time_left_after_drawing_ms",
822 (begin_impl_frame_args_.deadline - estimated_draw_time).InMillisecondsF(),
823 "state",
824 AsValue());
825
826 return estimated_draw_time < begin_impl_frame_args_.deadline;
827 }
828
829 bool Scheduler::IsBeginMainFrameSentOrStarted() const {
830 return (state_machine_.commit_state() ==
831 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT ||
832 state_machine_.commit_state() ==
833 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED);
834 }
835
836 } // namespace cc
OLDNEW
« no previous file with comments | « cc/scheduler/scheduler.h ('k') | cc/scheduler/scheduler_settings.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698