Flutter Engine
vsync_waiter_ios.mm
Go to the documentation of this file.
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 #import "flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h"
6 
7 #include <utility>
8 
9 #include <Foundation/Foundation.h>
10 #include <QuartzCore/CADisplayLink.h>
11 #include <UIKit/UIKit.h>
12 #include <mach/mach_time.h>
13 
14 #include "flutter/common/task_runners.h"
15 #include "flutter/fml/logging.h"
16 #include "flutter/fml/trace_event.h"
17 
18 namespace flutter {
19 
21  : VsyncWaiter(std::move(task_runners)) {
22  auto callback = [this](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) {
23  const fml::TimePoint start_time = recorder->GetVsyncStartTime();
24  const fml::TimePoint target_time = recorder->GetVsyncTargetTime();
25  FireCallback(start_time, target_time, true);
26  };
27  client_ =
30 }
31 
33  // This way, we will get no more callbacks from the display link that holds a weak (non-nilling)
34  // reference to this C++ object.
35  [client_.get() invalidate];
36 }
37 
38 void VsyncWaiterIOS::AwaitVSync() {
39  [client_.get() await];
40 }
41 
42 } // namespace flutter
43 
44 @implementation VSyncClient {
47 }
48 
49 - (instancetype)initWithTaskRunner:(fml::RefPtr<fml::TaskRunner>)task_runner
50  callback:(flutter::VsyncWaiter::Callback)callback {
51  self = [super init];
52 
53  if (self) {
54  callback_ = std::move(callback);
56  [[CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)] retain]
57  };
58  display_link_.get().paused = YES;
59 
60  task_runner->PostTask([client = [self retain]]() {
61  [client->display_link_.get() addToRunLoop:[NSRunLoop currentRunLoop]
62  forMode:NSRunLoopCommonModes];
63  [client release];
64  });
65  }
66 
67  return self;
68 }
69 
70 - (void)await {
71  display_link_.get().paused = NO;
72 }
73 
74 - (void)onDisplayLink:(CADisplayLink*)link {
75  TRACE_EVENT0("flutter", "VSYNC");
76 
77  CFTimeInterval delay = CACurrentMediaTime() - link.timestamp;
79 
80  CFTimeInterval duration;
81  if (@available(iOS 10.0, *)) {
82  duration = link.targetTimestamp - link.timestamp;
83  } else {
84  duration = link.duration;
85  }
86  fml::TimePoint frame_target_time = frame_start_time + fml::TimeDelta::FromSecondsF(duration);
87 
88  std::unique_ptr<flutter::FrameTimingsRecorder> recorder =
89  std::make_unique<flutter::FrameTimingsRecorder>();
90  recorder->RecordVsync(frame_start_time, frame_target_time);
91  display_link_.get().paused = YES;
92 
93  callback_(std::move(recorder));
94 }
95 
96 - (void)invalidate {
97  [display_link_.get() invalidate];
98 }
99 
100 - (void)dealloc {
101  [self invalidate];
102 
103  [super dealloc];
104 }
105 
106 @end
107 
108 @implementation DisplayLinkManager
109 
111  if (@available(iOS 10.3, *)) {
113  [[CADisplayLink displayLinkWithTarget:[[DisplayLinkManager new] autorelease]
114  selector:@selector(onDisplayLink:)] retain]
115  };
116  display_link.get().paused = YES;
117  auto preferredFPS = display_link.get().preferredFramesPerSecond; // iOS 10.0
118 
119  // From Docs:
120  // The default value for preferredFramesPerSecond is 0. When this value is 0, the preferred
121  // frame rate is equal to the maximum refresh rate of the display, as indicated by the
122  // maximumFramesPerSecond property.
123 
124  if (preferredFPS != 0) {
125  return preferredFPS;
126  }
127 
128  return [UIScreen mainScreen].maximumFramesPerSecond; // iOS 10.3
129  } else {
130  return 60.0;
131  }
132 }
133 
134 - (void)onDisplayLink:(CADisplayLink*)link {
135  // no-op.
136 }
137 
138 @end
VsyncWaiter(TaskRunners task_runners)
Definition: vsync_waiter.cc:37
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:90
fml::scoped_nsobject< CADisplayLink > display_link_
static constexpr TimeDelta FromSecondsF(double seconds)
Definition: time_delta.h:53
Definition: ref_ptr.h:252
void FireCallback(fml::TimePoint frame_start_time, fml::TimePoint frame_target_time, bool pause_secondary_tasks=true)
Definition: vsync_waiter.cc:97
FlKeyEvent FlKeyResponderAsyncCallback callback
Definition: ascii_trie.cc:9
VsyncWaiterIOS(flutter::TaskRunners task_runners)
fml::RefPtr< fml::TaskRunner > GetUITaskRunner() const
Definition: task_runners.cc:34
const TaskRunners task_runners_
Definition: vsync_waiter.h:41
std::function< void(std::unique_ptr< FrameTimingsRecorder >)> Callback
Definition: vsync_waiter.h:23
static TimePoint Now()
Definition: time_point.cc:39