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 #include <utility>
9 #include <vector>
10
11 #include "base/auto_reset.h"
12 #include "base/bind.h"
13 #include "base/check_op.h"
14 #include "base/location.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/trace_event/trace_event.h"
17 #include "base/trace_event/traced_value.h"
18 #include "cc/base/devtools_instrumentation.h"
19 #include "cc/metrics/begin_main_frame_metrics.h"
20 #include "cc/metrics/compositor_timing_history.h"
21 #include "components/viz/common/frame_sinks/delay_based_time_source.h"
22 #include "services/tracing/public/cpp/perfetto/macros.h"
23 #include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_compositor_scheduler_state.pbzero.h"
24
25 namespace cc {
26
27 namespace {
28 // This is a fudge factor we subtract from the deadline to account
29 // for message latency and kernel scheduling variability.
30 const base::TimeDelta kDeadlineFudgeFactor =
31 base::TimeDelta::FromMicroseconds(1000);
32 } // namespace
33
Scheduler(SchedulerClient * client,const SchedulerSettings & settings,int layer_tree_host_id,base::SingleThreadTaskRunner * task_runner,std::unique_ptr<CompositorTimingHistory> compositor_timing_history)34 Scheduler::Scheduler(
35 SchedulerClient* client,
36 const SchedulerSettings& settings,
37 int layer_tree_host_id,
38 base::SingleThreadTaskRunner* task_runner,
39 std::unique_ptr<CompositorTimingHistory> compositor_timing_history)
40 : settings_(settings),
41 client_(client),
42 layer_tree_host_id_(layer_tree_host_id),
43 task_runner_(task_runner),
44 compositor_timing_history_(std::move(compositor_timing_history)),
45 begin_impl_frame_tracker_(FROM_HERE),
46 state_machine_(settings) {
47 TRACE_EVENT1("cc", "Scheduler::Scheduler", "settings", settings_.AsValue());
48 DCHECK(client_);
49 DCHECK(!state_machine_.BeginFrameNeeded());
50
51 // We want to handle animate_only BeginFrames.
52 wants_animate_only_begin_frames_ = true;
53
54 ProcessScheduledActions();
55 }
56
~Scheduler()57 Scheduler::~Scheduler() {
58 SetBeginFrameSource(nullptr);
59 }
60
Stop()61 void Scheduler::Stop() {
62 stopped_ = true;
63 }
64
SetNeedsImplSideInvalidation(bool needs_first_draw_on_activation)65 void Scheduler::SetNeedsImplSideInvalidation(
66 bool needs_first_draw_on_activation) {
67 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
68 "Scheduler::SetNeedsImplSideInvalidation",
69 "needs_first_draw_on_activation",
70 needs_first_draw_on_activation);
71 state_machine_.SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
72 ProcessScheduledActions();
73 }
74
Now() const75 base::TimeTicks Scheduler::Now() const {
76 base::TimeTicks now = base::TimeTicks::Now();
77 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.now"),
78 "Scheduler::Now", "now", now);
79 return now;
80 }
81
SetVisible(bool visible)82 void Scheduler::SetVisible(bool visible) {
83 state_machine_.SetVisible(visible);
84 UpdateCompositorTimingHistoryRecordingEnabled();
85 ProcessScheduledActions();
86 }
87
SetCanDraw(bool can_draw)88 void Scheduler::SetCanDraw(bool can_draw) {
89 state_machine_.SetCanDraw(can_draw);
90 ProcessScheduledActions();
91 }
92
NotifyReadyToActivate()93 void Scheduler::NotifyReadyToActivate() {
94 if (state_machine_.NotifyReadyToActivate())
95 compositor_timing_history_->ReadyToActivate();
96
97 ProcessScheduledActions();
98 }
99
NotifyReadyToDraw()100 void Scheduler::NotifyReadyToDraw() {
101 // Future work might still needed for crbug.com/352894.
102 state_machine_.NotifyReadyToDraw();
103 ProcessScheduledActions();
104 }
105
SetBeginFrameSource(viz::BeginFrameSource * source)106 void Scheduler::SetBeginFrameSource(viz::BeginFrameSource* source) {
107 if (source == begin_frame_source_)
108 return;
109 if (begin_frame_source_ && observing_begin_frame_source_)
110 begin_frame_source_->RemoveObserver(this);
111 begin_frame_source_ = source;
112 if (!begin_frame_source_)
113 return;
114 if (observing_begin_frame_source_)
115 begin_frame_source_->AddObserver(this);
116 }
117
NotifyAnimationWorkletStateChange(AnimationWorkletState state,TreeType tree)118 void Scheduler::NotifyAnimationWorkletStateChange(AnimationWorkletState state,
119 TreeType tree) {
120 state_machine_.NotifyAnimationWorkletStateChange(state, tree);
121 ProcessScheduledActions();
122 }
123
NotifyPaintWorkletStateChange(PaintWorkletState state)124 void Scheduler::NotifyPaintWorkletStateChange(PaintWorkletState state) {
125 state_machine_.NotifyPaintWorkletStateChange(state);
126 ProcessScheduledActions();
127 }
128
SetNeedsBeginMainFrame()129 void Scheduler::SetNeedsBeginMainFrame() {
130 state_machine_.SetNeedsBeginMainFrame();
131 ProcessScheduledActions();
132 }
133
SetNeedsOneBeginImplFrame()134 void Scheduler::SetNeedsOneBeginImplFrame() {
135 state_machine_.SetNeedsOneBeginImplFrame();
136 ProcessScheduledActions();
137 }
138
SetNeedsRedraw()139 void Scheduler::SetNeedsRedraw() {
140 state_machine_.SetNeedsRedraw();
141 ProcessScheduledActions();
142 }
143
SetNeedsPrepareTiles()144 void Scheduler::SetNeedsPrepareTiles() {
145 DCHECK(!IsInsideAction(SchedulerStateMachine::Action::PREPARE_TILES));
146 state_machine_.SetNeedsPrepareTiles();
147 ProcessScheduledActions();
148 }
149
DidSubmitCompositorFrame(uint32_t frame_token,EventMetricsSet events_metrics)150 void Scheduler::DidSubmitCompositorFrame(uint32_t frame_token,
151 EventMetricsSet events_metrics) {
152 compositor_timing_history_->DidSubmitCompositorFrame(
153 frame_token, begin_main_frame_args_.frame_id,
154 last_activate_origin_frame_args_.frame_id, std::move(events_metrics));
155 state_machine_.DidSubmitCompositorFrame();
156
157 // There is no need to call ProcessScheduledActions here because
158 // submitting a CompositorFrame should not trigger any new actions.
159 if (!inside_process_scheduled_actions_) {
160 DCHECK_EQ(state_machine_.NextAction(), SchedulerStateMachine::Action::NONE);
161 }
162 }
163
DidReceiveCompositorFrameAck()164 void Scheduler::DidReceiveCompositorFrameAck() {
165 DCHECK_GT(state_machine_.pending_submit_frames(), 0);
166 compositor_timing_history_->DidReceiveCompositorFrameAck();
167 state_machine_.DidReceiveCompositorFrameAck();
168 ProcessScheduledActions();
169 }
170
SetTreePrioritiesAndScrollState(TreePriority tree_priority,ScrollHandlerState scroll_handler_state)171 void Scheduler::SetTreePrioritiesAndScrollState(
172 TreePriority tree_priority,
173 ScrollHandlerState scroll_handler_state) {
174 compositor_timing_history_->SetTreePriority(tree_priority);
175 state_machine_.SetTreePrioritiesAndScrollState(tree_priority,
176 scroll_handler_state);
177 ProcessScheduledActions();
178 }
179
NotifyReadyToCommit(std::unique_ptr<BeginMainFrameMetrics> details)180 void Scheduler::NotifyReadyToCommit(
181 std::unique_ptr<BeginMainFrameMetrics> details) {
182 TRACE_EVENT0("cc", "Scheduler::NotifyReadyToCommit");
183 compositor_timing_history_->NotifyReadyToCommit(std::move(details));
184 state_machine_.NotifyReadyToCommit();
185 ProcessScheduledActions();
186 }
187
DidCommit()188 void Scheduler::DidCommit() {
189 compositor_timing_history_->DidCommit();
190 }
191
BeginMainFrameAborted(CommitEarlyOutReason reason)192 void Scheduler::BeginMainFrameAborted(CommitEarlyOutReason reason) {
193 TRACE_EVENT1("cc", "Scheduler::BeginMainFrameAborted", "reason",
194 CommitEarlyOutReasonToString(reason));
195 compositor_timing_history_->BeginMainFrameAborted(
196 last_dispatched_begin_main_frame_args_.frame_id, reason);
197 state_machine_.BeginMainFrameAborted(reason);
198 ProcessScheduledActions();
199 }
200
WillPrepareTiles()201 void Scheduler::WillPrepareTiles() {
202 compositor_timing_history_->WillPrepareTiles();
203 }
204
DidPrepareTiles()205 void Scheduler::DidPrepareTiles() {
206 compositor_timing_history_->DidPrepareTiles();
207 state_machine_.DidPrepareTiles();
208 }
209
DidPresentCompositorFrame(uint32_t frame_token,const viz::FrameTimingDetails & details)210 void Scheduler::DidPresentCompositorFrame(
211 uint32_t frame_token,
212 const viz::FrameTimingDetails& details) {
213 compositor_timing_history_->DidPresentCompositorFrame(frame_token, details);
214 }
215
DidLoseLayerTreeFrameSink()216 void Scheduler::DidLoseLayerTreeFrameSink() {
217 TRACE_EVENT0("cc", "Scheduler::DidLoseLayerTreeFrameSink");
218 state_machine_.DidLoseLayerTreeFrameSink();
219 UpdateCompositorTimingHistoryRecordingEnabled();
220 ProcessScheduledActions();
221 }
222
DidCreateAndInitializeLayerTreeFrameSink()223 void Scheduler::DidCreateAndInitializeLayerTreeFrameSink() {
224 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeLayerTreeFrameSink");
225 DCHECK(!observing_begin_frame_source_);
226 DCHECK(begin_impl_frame_deadline_task_.IsCancelled());
227 state_machine_.DidCreateAndInitializeLayerTreeFrameSink();
228 compositor_timing_history_->DidCreateAndInitializeLayerTreeFrameSink();
229 UpdateCompositorTimingHistoryRecordingEnabled();
230 ProcessScheduledActions();
231 }
232
NotifyBeginMainFrameStarted(base::TimeTicks main_thread_start_time)233 void Scheduler::NotifyBeginMainFrameStarted(
234 base::TimeTicks main_thread_start_time) {
235 TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted");
236 compositor_timing_history_->BeginMainFrameStarted(main_thread_start_time);
237 }
238
LastBeginImplFrameTime()239 base::TimeTicks Scheduler::LastBeginImplFrameTime() {
240 return begin_impl_frame_tracker_.Current().frame_time;
241 }
242
BeginMainFrameNotExpectedUntil(base::TimeTicks time)243 void Scheduler::BeginMainFrameNotExpectedUntil(base::TimeTicks time) {
244 TRACE_EVENT1("cc", "Scheduler::BeginMainFrameNotExpectedUntil",
245 "remaining_time", (time - Now()).InMillisecondsF());
246
247 DCHECK(!inside_scheduled_action_);
248 base::AutoReset<bool> mark_inside(&inside_scheduled_action_, true);
249 client_->ScheduledActionBeginMainFrameNotExpectedUntil(time);
250 }
251
BeginMainFrameNotExpectedSoon()252 void Scheduler::BeginMainFrameNotExpectedSoon() {
253 TRACE_EVENT0("cc", "Scheduler::BeginMainFrameNotExpectedSoon");
254
255 DCHECK(!inside_scheduled_action_);
256 base::AutoReset<bool> mark_inside(&inside_scheduled_action_, true);
257 client_->SendBeginMainFrameNotExpectedSoon();
258 }
259
StartOrStopBeginFrames()260 void Scheduler::StartOrStopBeginFrames() {
261 if (state_machine_.begin_impl_frame_state() !=
262 SchedulerStateMachine::BeginImplFrameState::IDLE) {
263 return;
264 }
265
266 bool needs_begin_frames = state_machine_.BeginFrameNeeded();
267 if (needs_begin_frames == observing_begin_frame_source_)
268 return;
269
270 if (needs_begin_frames) {
271 observing_begin_frame_source_ = true;
272 if (begin_frame_source_)
273 begin_frame_source_->AddObserver(this);
274 devtools_instrumentation::NeedsBeginFrameChanged(layer_tree_host_id_, true);
275 } else {
276 observing_begin_frame_source_ = false;
277 if (begin_frame_source_)
278 begin_frame_source_->RemoveObserver(this);
279 // We're going idle so drop pending begin frame.
280 if (settings_.using_synchronous_renderer_compositor)
281 FinishImplFrameSynchronous();
282 CancelPendingBeginFrameTask();
283
284 compositor_timing_history_->BeginImplFrameNotExpectedSoon();
285 devtools_instrumentation::NeedsBeginFrameChanged(layer_tree_host_id_,
286 false);
287 client_->WillNotReceiveBeginFrame();
288 }
289 }
290
CancelPendingBeginFrameTask()291 void Scheduler::CancelPendingBeginFrameTask() {
292 if (pending_begin_frame_args_.IsValid()) {
293 TRACE_EVENT_INSTANT0("cc", "Scheduler::BeginFrameDropped",
294 TRACE_EVENT_SCOPE_THREAD);
295 SendDidNotProduceFrame(pending_begin_frame_args_,
296 FrameSkippedReason::kNoDamage);
297 // Make pending begin frame invalid so that we don't accidentally use it.
298 pending_begin_frame_args_ = viz::BeginFrameArgs();
299 }
300 pending_begin_frame_task_.Cancel();
301 }
302
PostPendingBeginFrameTask()303 void Scheduler::PostPendingBeginFrameTask() {
304 bool is_idle = state_machine_.begin_impl_frame_state() ==
305 SchedulerStateMachine::BeginImplFrameState::IDLE;
306 bool needs_begin_frames = state_machine_.BeginFrameNeeded();
307 // We only post one pending begin frame task at a time, but we update the args
308 // whenever we get a new begin frame.
309 bool has_pending_begin_frame_args = pending_begin_frame_args_.IsValid();
310 bool has_no_pending_begin_frame_task =
311 pending_begin_frame_task_.IsCancelled();
312
313 if (is_idle && needs_begin_frames && has_pending_begin_frame_args &&
314 has_no_pending_begin_frame_task) {
315 pending_begin_frame_task_.Reset(base::BindOnce(
316 &Scheduler::HandlePendingBeginFrame, base::Unretained(this)));
317 task_runner_->PostTask(FROM_HERE, pending_begin_frame_task_.callback());
318 }
319 }
320
OnBeginFrameSourcePausedChanged(bool paused)321 void Scheduler::OnBeginFrameSourcePausedChanged(bool paused) {
322 if (state_machine_.begin_frame_source_paused() == paused)
323 return;
324 TRACE_EVENT_INSTANT1("cc", "Scheduler::SetBeginFrameSourcePaused",
325 TRACE_EVENT_SCOPE_THREAD, "paused", paused);
326 state_machine_.SetBeginFrameSourcePaused(paused);
327 ProcessScheduledActions();
328 }
329
330 // BeginFrame is the mechanism that tells us that now is a good time to start
331 // making a frame. Usually this means that user input for the frame is complete.
332 // If the scheduler is busy, we queue the BeginFrame to be handled later as
333 // a BeginRetroFrame.
OnBeginFrameDerivedImpl(const viz::BeginFrameArgs & args)334 bool Scheduler::OnBeginFrameDerivedImpl(const viz::BeginFrameArgs& args) {
335 TRACE_EVENT1("cc,benchmark", "Scheduler::BeginFrame", "args", args.AsValue());
336
337 // If the begin frame interval is different than last frame and bigger than
338 // zero then let |client_| know about the new interval for animations. In
339 // theory the interval should always be bigger than zero but the value is
340 // provided by APIs outside our control.
341 if (args.interval != last_frame_interval_ &&
342 args.interval > base::TimeDelta()) {
343 last_frame_interval_ = args.interval;
344 client_->FrameIntervalUpdated(last_frame_interval_);
345 }
346
347 // Drop the BeginFrame if we don't need one.
348 if (!state_machine_.BeginFrameNeeded()) {
349 TRACE_EVENT_INSTANT0("cc", "Scheduler::BeginFrameDropped",
350 TRACE_EVENT_SCOPE_THREAD);
351 // Since we don't use the BeginFrame, we may later receive the same
352 // BeginFrame again. Thus, we can't confirm it at this point, even though we
353 // don't have any updates right now.
354 SendDidNotProduceFrame(args, FrameSkippedReason::kNoDamage);
355 return false;
356 }
357
358 // Trace this begin frame time through the Chrome stack
359 TRACE_EVENT_FLOW_BEGIN0(
360 TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"),
361 "viz::BeginFrameArgs", args.frame_time.since_origin().InMicroseconds());
362
363 if (settings_.using_synchronous_renderer_compositor) {
364 BeginImplFrameSynchronous(args);
365 return true;
366 }
367
368 bool inside_previous_begin_frame =
369 state_machine_.begin_impl_frame_state() ==
370 SchedulerStateMachine::BeginImplFrameState::INSIDE_BEGIN_FRAME;
371
372 if (inside_process_scheduled_actions_ || inside_previous_begin_frame ||
373 pending_begin_frame_args_.IsValid()) {
374 // The BFS can send a begin frame while scheduler is processing previous
375 // frame, or a MISSED begin frame inside the ProcessScheduledActions loop
376 // when AddObserver is called. The BFS (e.g. mojo) may queue up many begin
377 // frame calls, but we only want to process the last one. Saving the args,
378 // and posting a task achieves that.
379 if (pending_begin_frame_args_.IsValid()) {
380 TRACE_EVENT_INSTANT0("cc", "Scheduler::BeginFrameDropped",
381 TRACE_EVENT_SCOPE_THREAD);
382 SendDidNotProduceFrame(pending_begin_frame_args_,
383 FrameSkippedReason::kRecoverLatency);
384 }
385 pending_begin_frame_args_ = args;
386 // ProcessScheduledActions() will post the previous frame's deadline if it
387 // hasn't run yet, or post the begin frame task if the previous frame's
388 // deadline has already run. If we're already inside
389 // ProcessScheduledActions() this call will be a nop and the above will
390 // happen at end of the top most call to ProcessScheduledActions().
391 ProcessScheduledActions();
392 } else {
393 // This starts the begin frame immediately, and puts us in the
394 // INSIDE_BEGIN_FRAME state, so if the message loop calls a bunch of
395 // BeginFrames immediately after this call, they will be posted as a single
396 // task, and all but the last BeginFrame will be dropped.
397 BeginImplFrameWithDeadline(args);
398 }
399 return true;
400 }
401
SetVideoNeedsBeginFrames(bool video_needs_begin_frames)402 void Scheduler::SetVideoNeedsBeginFrames(bool video_needs_begin_frames) {
403 state_machine_.SetVideoNeedsBeginFrames(video_needs_begin_frames);
404 ProcessScheduledActions();
405 }
406
OnDrawForLayerTreeFrameSink(bool resourceless_software_draw,bool skip_draw)407 void Scheduler::OnDrawForLayerTreeFrameSink(bool resourceless_software_draw,
408 bool skip_draw) {
409 DCHECK(settings_.using_synchronous_renderer_compositor);
410 if (state_machine_.begin_impl_frame_state() ==
411 SchedulerStateMachine::BeginImplFrameState::INSIDE_BEGIN_FRAME) {
412 DCHECK(needs_finish_frame_for_synchronous_compositor_);
413 } else {
414 DCHECK_EQ(state_machine_.begin_impl_frame_state(),
415 SchedulerStateMachine::BeginImplFrameState::IDLE);
416 DCHECK(!needs_finish_frame_for_synchronous_compositor_);
417 }
418 DCHECK(begin_impl_frame_deadline_task_.IsCancelled());
419
420 state_machine_.SetResourcelessSoftwareDraw(resourceless_software_draw);
421 state_machine_.SetSkipDraw(skip_draw);
422 OnBeginImplFrameDeadline();
423
424 state_machine_.OnBeginImplFrameIdle();
425 ProcessScheduledActions();
426 state_machine_.SetResourcelessSoftwareDraw(false);
427 }
428
429 // This is separate from BeginImplFrameWithDeadline() because we only want at
430 // most one outstanding task even if |pending_begin_frame_args_| changes.
HandlePendingBeginFrame()431 void Scheduler::HandlePendingBeginFrame() {
432 DCHECK(pending_begin_frame_args_.IsValid());
433 viz::BeginFrameArgs args = pending_begin_frame_args_;
434 pending_begin_frame_args_ = viz::BeginFrameArgs();
435 pending_begin_frame_task_.Cancel();
436
437 BeginImplFrameWithDeadline(args);
438 }
439
BeginImplFrameWithDeadline(const viz::BeginFrameArgs & args)440 void Scheduler::BeginImplFrameWithDeadline(const viz::BeginFrameArgs& args) {
441 DCHECK(pending_begin_frame_task_.IsCancelled());
442 DCHECK(!pending_begin_frame_args_.IsValid());
443
444 DCHECK_EQ(state_machine_.begin_impl_frame_state(),
445 SchedulerStateMachine::BeginImplFrameState::IDLE);
446
447 bool main_thread_is_in_high_latency_mode =
448 state_machine_.main_thread_missed_last_deadline();
449 TRACE_EVENT2("cc,benchmark", "Scheduler::BeginImplFrame", "args",
450 args.AsValue(), "main_thread_missed_last_deadline",
451 main_thread_is_in_high_latency_mode);
452 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
453 "MainThreadLatency", main_thread_is_in_high_latency_mode);
454
455 base::TimeTicks now = Now();
456 // Discard missed begin frames if they are too late. In full-pipe mode, we
457 // ignore BeginFrame deadlines.
458 if (!settings_.wait_for_all_pipeline_stages_before_draw &&
459 args.type == viz::BeginFrameArgs::MISSED && args.deadline < now) {
460 TRACE_EVENT_INSTANT0("cc", "Scheduler::MissedBeginFrameDropped",
461 TRACE_EVENT_SCOPE_THREAD);
462 skipped_last_frame_missed_exceeded_deadline_ = true;
463 SendDidNotProduceFrame(args, FrameSkippedReason::kRecoverLatency);
464 return;
465 }
466 skipped_last_frame_missed_exceeded_deadline_ = false;
467
468 viz::BeginFrameArgs adjusted_args = args;
469 adjusted_args.deadline -= compositor_timing_history_->DrawDurationEstimate();
470 adjusted_args.deadline -= kDeadlineFudgeFactor;
471
472 // TODO(khushalsagar): We need to consider the deadline fudge factor here to
473 // match the deadline used in BeginImplFrameDeadlineMode::REGULAR mode
474 // (used in the case where the impl thread needs to redraw). In the case where
475 // main_frame_to_active is fast, we should consider using
476 // BeginImplFrameDeadlineMode::LATE instead to avoid putting the main
477 // thread in high latency mode. See crbug.com/753146.
478 base::TimeDelta bmf_to_activate_threshold =
479 adjusted_args.interval -
480 compositor_timing_history_->DrawDurationEstimate() - kDeadlineFudgeFactor;
481
482 // An estimate of time from starting the main frame on the main thread to when
483 // the resulting pending tree is activated. Note that this excludes the
484 // durations where progress is blocked due to back pressure in the pipeline
485 // (ready to commit to commit, ready to activate to activate, etc.)
486 base::TimeDelta bmf_start_to_activate =
487 compositor_timing_history_
488 ->BeginMainFrameStartToReadyToCommitDurationEstimate() +
489 compositor_timing_history_->CommitDurationEstimate() +
490 compositor_timing_history_->CommitToReadyToActivateDurationEstimate() +
491 compositor_timing_history_->ActivateDurationEstimate();
492
493 base::TimeDelta bmf_to_activate_estimate_critical =
494 bmf_start_to_activate +
495 compositor_timing_history_->BeginMainFrameQueueDurationCriticalEstimate();
496 state_machine_.SetCriticalBeginMainFrameToActivateIsFast(
497 bmf_to_activate_estimate_critical < bmf_to_activate_threshold);
498
499 // Update the BeginMainFrame args now that we know whether the main
500 // thread will be on the critical path or not.
501 begin_main_frame_args_ = adjusted_args;
502 begin_main_frame_args_.on_critical_path = !ImplLatencyTakesPriority();
503
504 // If we expect the main thread to respond within this frame, defer the
505 // invalidation to merge it with the incoming main frame. Even if the response
506 // is delayed such that the raster can not be completed within this frame's
507 // draw, its better to delay the invalidation than blocking the pipeline with
508 // an extra pending tree update to be flushed.
509 base::TimeDelta time_since_main_frame_sent;
510 if (compositor_timing_history_->begin_main_frame_sent_time() !=
511 base::TimeTicks()) {
512 time_since_main_frame_sent =
513 now - compositor_timing_history_->begin_main_frame_sent_time();
514 }
515 base::TimeDelta bmf_sent_to_ready_to_commit_estimate =
516 compositor_timing_history_
517 ->BeginMainFrameStartToReadyToCommitDurationEstimate();
518 if (begin_main_frame_args_.on_critical_path) {
519 bmf_sent_to_ready_to_commit_estimate +=
520 compositor_timing_history_
521 ->BeginMainFrameQueueDurationCriticalEstimate();
522 } else {
523 bmf_sent_to_ready_to_commit_estimate +=
524 compositor_timing_history_
525 ->BeginMainFrameQueueDurationNotCriticalEstimate();
526 }
527
528 bool main_thread_response_expected_before_deadline;
529 if (time_since_main_frame_sent > bmf_to_activate_threshold) {
530 // If the response to a main frame is pending past the desired duration
531 // then proactively assume that the main thread is slow instead of late
532 // correction through the frame history.
533 main_thread_response_expected_before_deadline = false;
534 } else {
535 main_thread_response_expected_before_deadline =
536 bmf_sent_to_ready_to_commit_estimate - time_since_main_frame_sent <
537 bmf_to_activate_threshold;
538 }
539 state_machine_.set_should_defer_invalidation_for_fast_main_frame(
540 main_thread_response_expected_before_deadline);
541
542 base::TimeDelta bmf_to_activate_estimate = bmf_to_activate_estimate_critical;
543 if (!begin_main_frame_args_.on_critical_path) {
544 bmf_to_activate_estimate =
545 bmf_start_to_activate +
546 compositor_timing_history_
547 ->BeginMainFrameQueueDurationNotCriticalEstimate();
548 }
549 bool can_activate_before_deadline =
550 CanBeginMainFrameAndActivateBeforeDeadline(adjusted_args,
551 bmf_to_activate_estimate, now);
552
553 if (ShouldRecoverMainLatency(adjusted_args, can_activate_before_deadline)) {
554 TRACE_EVENT_INSTANT0("cc", "SkipBeginMainFrameToReduceLatency",
555 TRACE_EVENT_SCOPE_THREAD);
556 state_machine_.SetSkipNextBeginMainFrameToReduceLatency(true);
557 } else if (ShouldRecoverImplLatency(adjusted_args,
558 can_activate_before_deadline)) {
559 TRACE_EVENT_INSTANT0("cc", "SkipBeginImplFrameToReduceLatency",
560 TRACE_EVENT_SCOPE_THREAD);
561 skipped_last_frame_to_reduce_latency_ = true;
562 SendDidNotProduceFrame(args, FrameSkippedReason::kRecoverLatency);
563 return;
564 }
565
566 skipped_last_frame_to_reduce_latency_ = false;
567
568 BeginImplFrame(adjusted_args, now);
569 }
570
BeginImplFrameSynchronous(const viz::BeginFrameArgs & args)571 void Scheduler::BeginImplFrameSynchronous(const viz::BeginFrameArgs& args) {
572 // Finish the previous frame (if needed) before starting a new one.
573 FinishImplFrameSynchronous();
574
575 TRACE_EVENT1("cc,benchmark", "Scheduler::BeginImplFrame", "args",
576 args.AsValue());
577 // The main thread currently can't commit before we draw with the
578 // synchronous compositor, so never consider the BeginMainFrame fast.
579 state_machine_.SetCriticalBeginMainFrameToActivateIsFast(false);
580 begin_main_frame_args_ = args;
581 begin_main_frame_args_.on_critical_path = !ImplLatencyTakesPriority();
582
583 BeginImplFrame(args, Now());
584 compositor_timing_history_->WillFinishImplFrame(state_machine_.needs_redraw(),
585 args.frame_id);
586 // Delay the call to |FinishFrame()| if a draw is anticipated, so that it is
587 // called after the draw happens (in |OnDrawForLayerTreeFrameSink()|).
588 needs_finish_frame_for_synchronous_compositor_ = true;
589 if (!state_machine_.did_invalidate_layer_tree_frame_sink()) {
590 // If there was no invalidation, then finish the frame immediately.
591 FinishImplFrameSynchronous();
592 }
593 }
594
FinishImplFrame()595 void Scheduler::FinishImplFrame() {
596 DCHECK(!needs_finish_frame_for_synchronous_compositor_);
597 state_machine_.OnBeginImplFrameIdle();
598
599 // Send ack before calling ProcessScheduledActions() because it might send an
600 // ack for any pending begin frame if we are going idle after this. This
601 // ensures that the acks are sent in order.
602 if (!state_machine_.did_submit_in_last_frame()) {
603 bool is_waiting_on_main = state_machine_.begin_main_frame_state() !=
604 SchedulerStateMachine::BeginMainFrameState::IDLE;
605 SendDidNotProduceFrame(begin_impl_frame_tracker_.Current(),
606 is_waiting_on_main
607 ? FrameSkippedReason::kWaitingOnMain
608 : FrameSkippedReason::kNoDamage);
609 }
610
611 begin_impl_frame_tracker_.Finish();
612
613 ProcessScheduledActions();
614 DCHECK(!inside_scheduled_action_);
615 {
616 base::AutoReset<bool> mark_inside(&inside_scheduled_action_, true);
617 client_->DidFinishImplFrame(last_activate_origin_frame_args());
618 }
619
620 if (begin_frame_source_)
621 begin_frame_source_->DidFinishFrame(this);
622 }
623
SendDidNotProduceFrame(const viz::BeginFrameArgs & args,FrameSkippedReason reason)624 void Scheduler::SendDidNotProduceFrame(const viz::BeginFrameArgs& args,
625 FrameSkippedReason reason) {
626 if (last_begin_frame_ack_.frame_id == args.frame_id)
627 return;
628 last_begin_frame_ack_ = viz::BeginFrameAck(args, false /* has_damage */);
629 client_->DidNotProduceFrame(last_begin_frame_ack_, reason);
630 compositor_timing_history_->DidNotProduceFrame(args.frame_id, reason);
631 }
632
633 // BeginImplFrame starts a compositor frame that will wait up until a deadline
634 // for a BeginMainFrame+activation to complete before it times out and draws
635 // any asynchronous animation and scroll/pinch updates.
BeginImplFrame(const viz::BeginFrameArgs & args,base::TimeTicks now)636 void Scheduler::BeginImplFrame(const viz::BeginFrameArgs& args,
637 base::TimeTicks now) {
638 DCHECK_EQ(state_machine_.begin_impl_frame_state(),
639 SchedulerStateMachine::BeginImplFrameState::IDLE);
640 DCHECK(begin_impl_frame_deadline_task_.IsCancelled());
641 DCHECK(state_machine_.HasInitializedLayerTreeFrameSink());
642
643 {
644 DCHECK(!inside_scheduled_action_);
645 base::AutoReset<bool> mark_inside(&inside_scheduled_action_, true);
646
647 begin_impl_frame_tracker_.Start(args);
648 state_machine_.OnBeginImplFrame(args.frame_id, args.animate_only);
649 devtools_instrumentation::DidBeginFrame(layer_tree_host_id_);
650 compositor_timing_history_->WillBeginImplFrame(args, now);
651 bool has_damage =
652 client_->WillBeginImplFrame(begin_impl_frame_tracker_.Current());
653
654 if (!has_damage)
655 state_machine_.AbortDraw();
656 }
657
658 ProcessScheduledActions();
659 }
660
ScheduleBeginImplFrameDeadline()661 void Scheduler::ScheduleBeginImplFrameDeadline() {
662 using DeadlineMode = SchedulerStateMachine::BeginImplFrameDeadlineMode;
663 deadline_mode_ = state_machine_.CurrentBeginImplFrameDeadlineMode();
664
665 base::TimeTicks new_deadline;
666 switch (deadline_mode_) {
667 case DeadlineMode::NONE:
668 // NONE is returned when deadlines aren't used (synchronous compositor),
669 // or when outside a begin frame. In either case deadline task shouldn't
670 // be posted or should be cancelled already.
671 DCHECK(begin_impl_frame_deadline_task_.IsCancelled());
672 return;
673 case DeadlineMode::BLOCKED: {
674 // TODO(sunnyps): Posting the deadline for pending begin frame is required
675 // for browser compositor (commit_to_active_tree) to make progress in some
676 // cases. Change browser compositor deadline to LATE in state machine to
677 // fix this.
678 //
679 // TODO(sunnyps): Full pipeline mode should always go from blocking
680 // deadline to triggering deadline immediately, but DCHECKing for this
681 // causes layout test failures.
682 bool has_pending_begin_frame = pending_begin_frame_args_.IsValid();
683 if (has_pending_begin_frame) {
684 new_deadline = base::TimeTicks();
685 break;
686 } else {
687 begin_impl_frame_deadline_task_.Cancel();
688 return;
689 }
690 }
691 case DeadlineMode::LATE: {
692 // We are waiting for a commit without needing active tree draw or we
693 // have nothing to do.
694 new_deadline = begin_impl_frame_tracker_.Current().frame_time +
695 begin_impl_frame_tracker_.Current().interval;
696 // Send early DidNotProduceFrame if we don't expect to produce a frame
697 // soon so that display scheduler doesn't wait unnecessarily.
698 // Note: This will only send one DidNotProduceFrame ack per begin frame.
699 if (!state_machine_.NewActiveTreeLikely()) {
700 SendDidNotProduceFrame(begin_impl_frame_tracker_.Current(),
701 FrameSkippedReason::kNoDamage);
702 }
703 break;
704 }
705 case DeadlineMode::REGULAR:
706 // We are animating the active tree but we're also waiting for commit.
707 new_deadline = begin_impl_frame_tracker_.Current().deadline;
708 break;
709 case DeadlineMode::IMMEDIATE:
710 // Avoid using Now() for immediate deadlines because it's expensive, and
711 // this method is called in every ProcessScheduledActions() call. Using
712 // base::TimeTicks() achieves the same result.
713 new_deadline = base::TimeTicks();
714 break;
715 }
716
717 // Post deadline task only if we didn't have one already or something caused
718 // us to change the deadline.
719 bool has_no_deadline_task = begin_impl_frame_deadline_task_.IsCancelled();
720 if (has_no_deadline_task || new_deadline != deadline_) {
721 TRACE_EVENT2("cc", "Scheduler::ScheduleBeginImplFrameDeadline",
722 "new deadline", new_deadline, "deadline mode",
723 SchedulerStateMachine::BeginImplFrameDeadlineModeToString(
724 deadline_mode_));
725 deadline_ = new_deadline;
726 deadline_scheduled_at_ = Now();
727
728 begin_impl_frame_deadline_task_.Reset(base::BindOnce(
729 &Scheduler::OnBeginImplFrameDeadline, base::Unretained(this)));
730
731 base::TimeDelta delay =
732 std::max(deadline_ - deadline_scheduled_at_, base::TimeDelta());
733 task_runner_->PostDelayedTask(
734 FROM_HERE, begin_impl_frame_deadline_task_.callback(), delay);
735 }
736 }
737
OnBeginImplFrameDeadline()738 void Scheduler::OnBeginImplFrameDeadline() {
739 TRACE_EVENT0("cc,benchmark", "Scheduler::OnBeginImplFrameDeadline");
740 begin_impl_frame_deadline_task_.Cancel();
741 // We split the deadline actions up into two phases so the state machine
742 // has a chance to trigger actions that should occur durring and after
743 // the deadline separately. For example:
744 // * Sending the BeginMainFrame will not occur after the deadline in
745 // order to wait for more user-input before starting the next commit.
746 // * Creating a new OuputSurface will not occur during the deadline in
747 // order to allow the state machine to "settle" first.
748 if (!settings_.using_synchronous_renderer_compositor) {
749 compositor_timing_history_->WillFinishImplFrame(
750 state_machine_.needs_redraw(), begin_main_frame_args_.frame_id);
751 }
752
753 state_machine_.OnBeginImplFrameDeadline();
754 ProcessScheduledActions();
755
756 if (settings_.using_synchronous_renderer_compositor)
757 FinishImplFrameSynchronous();
758 else
759 FinishImplFrame();
760 }
761
FinishImplFrameSynchronous()762 void Scheduler::FinishImplFrameSynchronous() {
763 DCHECK(settings_.using_synchronous_renderer_compositor);
764 if (needs_finish_frame_for_synchronous_compositor_) {
765 needs_finish_frame_for_synchronous_compositor_ = false;
766 FinishImplFrame();
767 }
768 }
769
DrawIfPossible()770 void Scheduler::DrawIfPossible() {
771 DCHECK(!inside_scheduled_action_);
772 base::AutoReset<bool> mark_inside(&inside_scheduled_action_, true);
773 bool drawing_with_new_active_tree =
774 state_machine_.active_tree_needs_first_draw() &&
775 !state_machine_.previous_pending_tree_was_impl_side();
776 compositor_timing_history_->WillDraw();
777 state_machine_.WillDraw();
778 DrawResult result = client_->ScheduledActionDrawIfPossible();
779 state_machine_.DidDraw(result);
780 compositor_timing_history_->DidDraw(
781 drawing_with_new_active_tree,
782 client_->HasCustomPropertyAnimations());
783 }
784
DrawForced()785 void Scheduler::DrawForced() {
786 DCHECK(!inside_scheduled_action_);
787 base::AutoReset<bool> mark_inside(&inside_scheduled_action_, true);
788 bool drawing_with_new_active_tree =
789 state_machine_.active_tree_needs_first_draw() &&
790 !state_machine_.previous_pending_tree_was_impl_side();
791 compositor_timing_history_->WillDraw();
792 state_machine_.WillDraw();
793 DrawResult result = client_->ScheduledActionDrawForced();
794 state_machine_.DidDraw(result);
795 compositor_timing_history_->DidDraw(
796 drawing_with_new_active_tree,
797 client_->HasCustomPropertyAnimations());
798 }
799
SetDeferBeginMainFrame(bool defer_begin_main_frame)800 void Scheduler::SetDeferBeginMainFrame(bool defer_begin_main_frame) {
801 TRACE_EVENT1("cc", "Scheduler::SetDeferBeginMainFrame",
802 "defer_begin_main_frame", defer_begin_main_frame);
803 state_machine_.SetDeferBeginMainFrame(defer_begin_main_frame);
804 ProcessScheduledActions();
805 }
806
SetMainThreadWantsBeginMainFrameNotExpected(bool new_state)807 void Scheduler::SetMainThreadWantsBeginMainFrameNotExpected(bool new_state) {
808 state_machine_.SetMainThreadWantsBeginMainFrameNotExpectedMessages(new_state);
809 ProcessScheduledActions();
810 }
811
ProcessScheduledActions()812 void Scheduler::ProcessScheduledActions() {
813 // Do not perform actions during compositor shutdown.
814 if (stopped_)
815 return;
816
817 // We do not allow ProcessScheduledActions to be recursive.
818 // The top-level call will iteratively execute the next action for us anyway.
819 if (inside_process_scheduled_actions_ || inside_scheduled_action_)
820 return;
821
822 base::AutoReset<bool> mark_inside(&inside_process_scheduled_actions_, true);
823
824 SchedulerStateMachine::Action action;
825 do {
826 action = state_machine_.NextAction();
827 TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
828 "SchedulerStateMachine", [this](perfetto::EventContext ctx) {
829 this->AsProtozeroInto(ctx.event()->set_cc_scheduler_state());
830 });
831 base::AutoReset<SchedulerStateMachine::Action> mark_inside_action(
832 &inside_action_, action);
833 switch (action) {
834 case SchedulerStateMachine::Action::NONE:
835 break;
836 case SchedulerStateMachine::Action::SEND_BEGIN_MAIN_FRAME:
837 compositor_timing_history_->WillBeginMainFrame(begin_main_frame_args_);
838 state_machine_.WillSendBeginMainFrame();
839 client_->ScheduledActionSendBeginMainFrame(begin_main_frame_args_);
840 last_dispatched_begin_main_frame_args_ = begin_main_frame_args_;
841 break;
842 case SchedulerStateMachine::Action::
843 NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_UNTIL:
844 state_machine_.WillNotifyBeginMainFrameNotExpectedUntil();
845 BeginMainFrameNotExpectedUntil(begin_main_frame_args_.frame_time +
846 begin_main_frame_args_.interval);
847 break;
848 case SchedulerStateMachine::Action::
849 NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_SOON:
850 state_machine_.WillNotifyBeginMainFrameNotExpectedSoon();
851 BeginMainFrameNotExpectedSoon();
852 break;
853 case SchedulerStateMachine::Action::COMMIT: {
854 bool commit_has_no_updates = false;
855 state_machine_.WillCommit(commit_has_no_updates);
856 compositor_timing_history_->WillCommit();
857 client_->ScheduledActionCommit();
858 last_commit_origin_frame_args_ = last_dispatched_begin_main_frame_args_;
859 break;
860 }
861 case SchedulerStateMachine::Action::ACTIVATE_SYNC_TREE:
862 compositor_timing_history_->WillActivate();
863 state_machine_.WillActivate();
864 client_->ScheduledActionActivateSyncTree();
865 compositor_timing_history_->DidActivate();
866 last_activate_origin_frame_args_ = last_commit_origin_frame_args_;
867 break;
868 case SchedulerStateMachine::Action::PERFORM_IMPL_SIDE_INVALIDATION:
869 state_machine_.WillPerformImplSideInvalidation();
870 compositor_timing_history_->WillInvalidateOnImplSide();
871 client_->ScheduledActionPerformImplSideInvalidation();
872 break;
873 case SchedulerStateMachine::Action::DRAW_IF_POSSIBLE:
874 DrawIfPossible();
875 break;
876 case SchedulerStateMachine::Action::DRAW_FORCED:
877 DrawForced();
878 break;
879 case SchedulerStateMachine::Action::DRAW_ABORT: {
880 // No action is actually performed, but this allows the state machine to
881 // drain the pipeline without actually drawing.
882 state_machine_.AbortDraw();
883 break;
884 }
885 case SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION:
886 state_machine_.WillBeginLayerTreeFrameSinkCreation();
887 client_->ScheduledActionBeginLayerTreeFrameSinkCreation();
888 break;
889 case SchedulerStateMachine::Action::PREPARE_TILES:
890 state_machine_.WillPrepareTiles();
891 client_->ScheduledActionPrepareTiles();
892 break;
893 case SchedulerStateMachine::Action::INVALIDATE_LAYER_TREE_FRAME_SINK: {
894 state_machine_.WillInvalidateLayerTreeFrameSink();
895 client_->ScheduledActionInvalidateLayerTreeFrameSink(
896 state_machine_.RedrawPending());
897 break;
898 }
899 }
900 } while (action != SchedulerStateMachine::Action::NONE);
901
902 ScheduleBeginImplFrameDeadline();
903
904 PostPendingBeginFrameTask();
905 StartOrStopBeginFrames();
906 }
907
AsProtozeroInto(perfetto::protos::pbzero::ChromeCompositorSchedulerState * state) const908 void Scheduler::AsProtozeroInto(
909 perfetto::protos::pbzero::ChromeCompositorSchedulerState* state) const {
910 base::TimeTicks now = Now();
911
912 state_machine_.AsProtozeroInto(state->set_state_machine());
913
914 state->set_observing_begin_frame_source(observing_begin_frame_source_);
915 state->set_begin_impl_frame_deadline_task(
916 !begin_impl_frame_deadline_task_.IsCancelled());
917 state->set_pending_begin_frame_task(!pending_begin_frame_task_.IsCancelled());
918 state->set_skipped_last_frame_missed_exceeded_deadline(
919 skipped_last_frame_missed_exceeded_deadline_);
920 state->set_skipped_last_frame_to_reduce_latency(
921 skipped_last_frame_to_reduce_latency_);
922 state->set_inside_action(
923 SchedulerStateMachine::ActionToProtozeroEnum(inside_action_));
924 state->set_deadline_mode(
925 SchedulerStateMachine::BeginImplFrameDeadlineModeToProtozeroEnum(
926 deadline_mode_));
927
928 state->set_deadline_us(deadline_.since_origin().InMicroseconds());
929 state->set_deadline_scheduled_at_us(
930 deadline_scheduled_at_.since_origin().InMicroseconds());
931
932 state->set_now_us(Now().since_origin().InMicroseconds());
933 state->set_now_to_deadline_delta_us((deadline_ - Now()).InMicroseconds());
934 state->set_now_to_deadline_scheduled_at_delta_us(
935 (deadline_scheduled_at_ - Now()).InMicroseconds());
936
937 begin_impl_frame_tracker_.AsProtozeroInto(now,
938 state->set_begin_impl_frame_args());
939
940 BeginFrameObserverBase::AsProtozeroInto(
941 state->set_begin_frame_observer_state());
942
943 if (begin_frame_source_) {
944 begin_frame_source_->AsProtozeroInto(state->set_begin_frame_source_state());
945 }
946
947 compositor_timing_history_->AsProtozeroInto(
948 state->set_compositor_timing_history());
949 }
950
UpdateCompositorTimingHistoryRecordingEnabled()951 void Scheduler::UpdateCompositorTimingHistoryRecordingEnabled() {
952 compositor_timing_history_->SetRecordingEnabled(
953 state_machine_.HasInitializedLayerTreeFrameSink() &&
954 state_machine_.visible());
955 }
956
ShouldRecoverMainLatency(const viz::BeginFrameArgs & args,bool can_activate_before_deadline) const957 bool Scheduler::ShouldRecoverMainLatency(
958 const viz::BeginFrameArgs& args,
959 bool can_activate_before_deadline) const {
960 DCHECK(!settings_.using_synchronous_renderer_compositor);
961
962 if (!settings_.enable_main_latency_recovery)
963 return false;
964
965 // The main thread is in a low latency mode and there's no need to recover.
966 if (!state_machine_.main_thread_missed_last_deadline())
967 return false;
968
969 // When prioritizing impl thread latency, we currently put the
970 // main thread in a high latency mode. Don't try to fight it.
971 if (state_machine_.ImplLatencyTakesPriority())
972 return false;
973
974 // Ensure that we have data from at least one frame before attempting latency
975 // recovery. This prevents skipping of frames during loading where the main
976 // thread is likely slow but we assume it to be fast since we have no history.
977 static const int kMinNumberOfSamplesBeforeLatencyRecovery = 1;
978 if (compositor_timing_history_
979 ->begin_main_frame_start_to_ready_to_commit_sample_count() <
980 kMinNumberOfSamplesBeforeLatencyRecovery ||
981 compositor_timing_history_->commit_to_ready_to_activate_sample_count() <
982 kMinNumberOfSamplesBeforeLatencyRecovery) {
983 return false;
984 }
985
986 return can_activate_before_deadline;
987 }
988
ShouldRecoverImplLatency(const viz::BeginFrameArgs & args,bool can_activate_before_deadline) const989 bool Scheduler::ShouldRecoverImplLatency(
990 const viz::BeginFrameArgs& args,
991 bool can_activate_before_deadline) const {
992 DCHECK(!settings_.using_synchronous_renderer_compositor);
993
994 if (!settings_.enable_impl_latency_recovery)
995 return false;
996
997 // Disable impl thread latency recovery when using the unthrottled
998 // begin frame source since we will always get a BeginFrame before
999 // the swap ack and our heuristics below will not work.
1000 if (begin_frame_source_ && !begin_frame_source_->IsThrottled())
1001 return false;
1002
1003 // If we are swap throttled at the BeginFrame, that means the impl thread is
1004 // very likely in a high latency mode.
1005 bool impl_thread_is_likely_high_latency = state_machine_.IsDrawThrottled();
1006 if (!impl_thread_is_likely_high_latency)
1007 return false;
1008
1009 // The deadline may be in the past if our draw time is too long.
1010 bool can_draw_before_deadline = args.frame_time < args.deadline;
1011
1012 // When prioritizing impl thread latency, the deadline doesn't wait
1013 // for the main thread.
1014 if (state_machine_.ImplLatencyTakesPriority())
1015 return can_draw_before_deadline;
1016
1017 // If we only have impl-side updates, the deadline doesn't wait for
1018 // the main thread.
1019 if (state_machine_.OnlyImplSideUpdatesExpected())
1020 return can_draw_before_deadline;
1021
1022 // If we get here, we know the main thread is in a low-latency mode relative
1023 // to the impl thread. In this case, only try to also recover impl thread
1024 // latency if both the main and impl threads can run serially before the
1025 // deadline.
1026 return can_activate_before_deadline;
1027 }
1028
CanBeginMainFrameAndActivateBeforeDeadline(const viz::BeginFrameArgs & args,base::TimeDelta bmf_to_activate_estimate,base::TimeTicks now) const1029 bool Scheduler::CanBeginMainFrameAndActivateBeforeDeadline(
1030 const viz::BeginFrameArgs& args,
1031 base::TimeDelta bmf_to_activate_estimate,
1032 base::TimeTicks now) const {
1033 // Check if the main thread computation and commit can be finished before the
1034 // impl thread's deadline.
1035 base::TimeTicks estimated_draw_time = now + bmf_to_activate_estimate;
1036
1037 return estimated_draw_time < args.deadline;
1038 }
1039
IsBeginMainFrameSent() const1040 bool Scheduler::IsBeginMainFrameSent() const {
1041 return state_machine_.begin_main_frame_state() ==
1042 SchedulerStateMachine::BeginMainFrameState::SENT;
1043 }
1044
CurrentBeginFrameAckForActiveTree() const1045 viz::BeginFrameAck Scheduler::CurrentBeginFrameAckForActiveTree() const {
1046 return viz::BeginFrameAck(begin_main_frame_args_, true);
1047 }
1048
ClearHistory()1049 void Scheduler::ClearHistory() {
1050 // Ensure we reset decisions based on history from the previous navigation.
1051 state_machine_.SetSkipNextBeginMainFrameToReduceLatency(false);
1052 compositor_timing_history_->ClearHistory();
1053 ProcessScheduledActions();
1054 }
1055
1056 } // namespace cc
1057