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  client_([[VSyncClient alloc] initWithTaskRunner:task_runners_.GetUITaskRunner()
23  callback:std::bind(&VsyncWaiterIOS::FireCallback,
24  this,
25  std::placeholders::_1,
26  std::placeholders::_2)]) {}
27 
29  // This way, we will get no more callbacks from the display link that holds a weak (non-nilling)
30  // reference to this C++ object.
31  [client_.get() invalidate];
32 }
33 
34 void VsyncWaiterIOS::AwaitVSync() {
35  [client_.get() await];
36 }
37 
38 } // namespace flutter
39 
40 @implementation VSyncClient {
43 }
44 
45 - (instancetype)initWithTaskRunner:(fml::RefPtr<fml::TaskRunner>)task_runner
46  callback:(flutter::VsyncWaiter::Callback)callback {
47  self = [super init];
48 
49  if (self) {
50  callback_ = std::move(callback);
52  [[CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)] retain]
53  };
54  display_link_.get().paused = YES;
55 
56  task_runner->PostTask([client = [self retain]]() {
57  [client->display_link_.get() addToRunLoop:[NSRunLoop currentRunLoop]
58  forMode:NSRunLoopCommonModes];
59  [client release];
60  });
61  }
62 
63  return self;
64 }
65 
66 - (void)await {
67  display_link_.get().paused = NO;
68 }
69 
70 - (void)onDisplayLink:(CADisplayLink*)link {
71  TRACE_EVENT0("flutter", "VSYNC");
72 
73  CFTimeInterval delay = CACurrentMediaTime() - link.timestamp;
75  fml::TimePoint frame_target_time = frame_start_time + fml::TimeDelta::FromSecondsF(link.duration);
76 
77  display_link_.get().paused = YES;
78 
79  callback_(frame_start_time, frame_target_time);
80 }
81 
82 - (void)invalidate {
83  [display_link_.get() invalidate];
84 }
85 
86 - (void)dealloc {
87  [self invalidate];
88 
89  [super dealloc];
90 }
91 
92 @end
93 
94 @implementation DisplayLinkManager {
96 }
97 
98 - (instancetype)init {
99  self = [super init];
100 
101  if (self) {
103  [[CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)] retain]
104  };
105  display_link_.get().paused = YES;
106  }
107 
108  return self;
109 }
110 
111 - (double)displayRefreshRate {
112  if (@available(iOS 10.3, *)) {
113  auto preferredFPS = display_link_.get().preferredFramesPerSecond; // iOS 10.0
114 
115  // From Docs:
116  // The default value for preferredFramesPerSecond is 0. When this value is 0, the preferred
117  // frame rate is equal to the maximum refresh rate of the display, as indicated by the
118  // maximumFramesPerSecond property.
119 
120  if (preferredFPS != 0) {
121  return preferredFPS;
122  }
123 
124  return [UIScreen mainScreen].maximumFramesPerSecond; // iOS 10.3
125  } else {
126  return 60.0;
127  }
128 }
129 
130 - (void)onDisplayLink:(CADisplayLink*)link {
131  // no-op.
132 }
133 
134 - (void)dealloc {
135  [display_link_.get() invalidate];
136 
137  [super dealloc];
138 }
139 
140 @end
VsyncWaiter(TaskRunners task_runners)
Definition: vsync_waiter.cc:32
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:75
fml::scoped_nsobject< CADisplayLink > display_link_
static constexpr TimeDelta FromSecondsF(double seconds)
Definition: time_delta.h:53
std::function< void(fml::TimePoint frame_start_time, fml::TimePoint frame_target_time)> Callback
Definition: vsync_waiter.h:22
Definition: ref_ptr.h:252
Definition: ascii_trie.cc:9
TaskRunners task_runners_
VsyncWaiterIOS(flutter::TaskRunners task_runners)
static TimePoint Now()
Definition: time_point.cc:26