• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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