scheduler.cc 42 KB

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