1 // Copyright 2013 The Flutter 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 "vsync_waiter.h"
6
7 #include <lib/async/default.h>
8 #include "flutter/fml/trace_event.h"
9
10 #include "vsync_recorder.h"
11
12 namespace flutter_runner {
13
VsyncWaiter(std::string debug_label,zx_handle_t session_present_handle,flutter::TaskRunners task_runners)14 VsyncWaiter::VsyncWaiter(std::string debug_label,
15 zx_handle_t session_present_handle,
16 flutter::TaskRunners task_runners)
17 : flutter::VsyncWaiter(task_runners),
18 debug_label_(std::move(debug_label)),
19 session_wait_(session_present_handle, SessionPresentSignal),
20 weak_factory_(this) {
21 auto wait_handler = [&](async_dispatcher_t* dispatcher, //
22 async::Wait* wait, //
23 zx_status_t status, //
24 const zx_packet_signal_t* signal //
25 ) {
26 if (status != ZX_OK) {
27 FML_LOG(ERROR) << "Vsync wait failed.";
28 return;
29 }
30
31 wait->Cancel();
32
33 FireCallbackNow();
34 };
35
36 session_wait_.set_handler(wait_handler);
37 }
38
~VsyncWaiter()39 VsyncWaiter::~VsyncWaiter() {
40 session_wait_.Cancel();
41 }
42
SnapToNextPhase(fml::TimePoint value,fml::TimePoint phase,fml::TimeDelta interval)43 static fml::TimePoint SnapToNextPhase(fml::TimePoint value,
44 fml::TimePoint phase,
45 fml::TimeDelta interval) {
46 fml::TimeDelta offset = (phase - value) % interval;
47 if (offset < fml::TimeDelta::Zero()) {
48 offset = offset + interval;
49 }
50 return value + offset;
51 }
52
AwaitVSync()53 void VsyncWaiter::AwaitVSync() {
54 VsyncInfo vsync_info = VsyncRecorder::GetInstance().GetCurrentVsyncInfo();
55
56 fml::TimePoint now = fml::TimePoint::Now();
57 fml::TimePoint next_vsync = SnapToNextPhase(now, vsync_info.presentation_time,
58 vsync_info.presentation_interval);
59 task_runners_.GetUITaskRunner()->PostDelayedTask(
60 [self = weak_factory_.GetWeakPtr()] {
61 if (self) {
62 self->FireCallbackWhenSessionAvailable();
63 }
64 },
65 next_vsync - now);
66 }
67
FireCallbackWhenSessionAvailable()68 void VsyncWaiter::FireCallbackWhenSessionAvailable() {
69 TRACE_EVENT0("flutter", "VsyncWaiter::FireCallbackWhenSessionAvailable");
70 FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
71 if (session_wait_.Begin(async_get_default_dispatcher()) != ZX_OK) {
72 FML_LOG(ERROR) << "Could not begin wait for Vsync.";
73 }
74 }
75
FireCallbackNow()76 void VsyncWaiter::FireCallbackNow() {
77 FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
78
79 VsyncInfo vsync_info = VsyncRecorder::GetInstance().GetCurrentVsyncInfo();
80
81 fml::TimePoint now = fml::TimePoint::Now();
82 fml::TimePoint next_vsync = SnapToNextPhase(now, vsync_info.presentation_time,
83 vsync_info.presentation_interval);
84 fml::TimePoint previous_vsync = next_vsync - vsync_info.presentation_interval;
85
86 FireCallback(previous_vsync, next_vsync);
87 }
88
89 } // namespace flutter_runner
90