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