| Flutter macOS Embedder |

FlutterDisplayLinkTest.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/macos/framework/Source/FlutterDisplayLink.h"
6 #import "flutter/shell/platform/darwin/macos/framework/Source/FlutterRunLoop.h"
7
8 #import <AppKit/AppKit.h>
9 #include <numeric>
10
11 #include "flutter/fml/synchronization/waitable_event.h"
12 #include "flutter/testing/testing.h"
13
14 @interface TestDisplayLinkDelegate : NSObject <FlutterDisplayLinkDelegate> {
15 void (^_block)(CFTimeInterval timestamp, CFTimeInterval targetTimestamp);
16 }
17
18 - (instancetype)initWithBlock:(void (^)(CFTimeInterval timestamp,
19 CFTimeInterval targetTimestamp))block;
20
21 @end
22
23 @implementation TestDisplayLinkDelegate
24 - (instancetype)initWithBlock:(void (^__strong)(CFTimeInterval, CFTimeInterval))block {
25 if (self = [super init]) {
26 _block = block;
27 }
28 return self;
29 }
30
31 - (void)onDisplayLink:(CFTimeInterval)timestamp targetTimestamp:(CFTimeInterval)targetTimestamp {
32 _block(timestamp, targetTimestamp);
33 }
34
35 @end
36
37 class FlutterDisplayLinkTest : public testing::Test {
38 public:
39 void SetUp() override { [FlutterRunLoop ensureMainLoopInitialized]; }
40 };
41
42 TEST_F(FlutterDisplayLinkTest, ViewAddedToWindowFirst) {
43 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
44 styleMask:NSWindowStyleMaskTitled
45 backing:NSBackingStoreNonretained
46 defer:NO];
47 NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
48 [window setContentView:view];
49
50 __block BOOL signalled = NO;
51
52 TestDisplayLinkDelegate* delegate = [[TestDisplayLinkDelegate alloc]
53 initWithBlock:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp) {
54 signalled = YES;
55 }];
56
57 FlutterDisplayLink* displayLink = [FlutterDisplayLink displayLinkWithView:view];
58 displayLink.delegate = delegate;
59 displayLink.paused = NO;
60
61 while (!signalled) {
62 [FlutterRunLoop.mainRunLoop pollFlutterMessagesOnce];
63 }
64
65 [displayLink invalidate];
66 }
67
68 TEST_F(FlutterDisplayLinkTest, ViewAddedToWindowLater) {
69 NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
70
71 __block BOOL signalled = NO;
72
73 TestDisplayLinkDelegate* delegate = [[TestDisplayLinkDelegate alloc]
74 initWithBlock:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp) {
75 signalled = YES;
76 }];
77
78 FlutterDisplayLink* displayLink = [FlutterDisplayLink displayLinkWithView:view];
79 displayLink.delegate = delegate;
80 displayLink.paused = NO;
81
82 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
83 styleMask:NSWindowStyleMaskTitled
84 backing:NSBackingStoreNonretained
85 defer:NO];
86 [window setContentView:view];
87
88 while (!signalled) {
89 [FlutterRunLoop.mainRunLoop pollFlutterMessagesOnce];
90 }
91
92 [displayLink invalidate];
93 }
94
95 TEST_F(FlutterDisplayLinkTest, ViewRemovedFromWindow) {
96 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
97 styleMask:NSWindowStyleMaskTitled
98 backing:NSBackingStoreNonretained
99 defer:NO];
100 NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
101 [window setContentView:view];
102
103 __block BOOL signalled = NO;
104
105 TestDisplayLinkDelegate* delegate = [[TestDisplayLinkDelegate alloc]
106 initWithBlock:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp) {
107 signalled = YES;
108 }];
109
110 FlutterDisplayLink* displayLink = [FlutterDisplayLink displayLinkWithView:view];
111 displayLink.delegate = delegate;
112 displayLink.paused = NO;
113
114 while (!signalled) {
115 [FlutterRunLoop.mainRunLoop pollFlutterMessagesOnce];
116 }
117 displayLink.paused = YES;
118
119 signalled = false;
120
121 displayLink.paused = NO;
122
123 [window setContentView:nil];
124
125 CFTimeInterval start = CACurrentMediaTime();
126 while (CACurrentMediaTime() < start + 0.1) {
127 [FlutterRunLoop.mainRunLoop pollFlutterMessagesOnce];
128 }
129
130 EXPECT_FALSE(signalled);
131
132 [displayLink invalidate];
133 }
134
135 TEST_F(FlutterDisplayLinkTest, CVDisplayLinkInterval) {
136 CVDisplayLinkRef link;
137 CVDisplayLinkCreateWithCGDisplay(CGMainDisplayID(), &link);
138 __block CFTimeInterval last = 0;
139 auto intervals = std::make_shared<std::vector<CFTimeInterval>>();
140 auto event = std::make_shared<fml::AutoResetWaitableEvent>();
141 CVDisplayLinkSetOutputHandler(
142 link, ^(CVDisplayLinkRef displayLink, const CVTimeStamp* inNow,
143 const CVTimeStamp* inOutputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut) {
144 if (last != 0) {
145 intervals->push_back(CACurrentMediaTime() - last);
146 }
147 last = CACurrentMediaTime();
148 if (intervals->size() == 10) {
149 event->Signal();
150 }
151 return 0;
152 });
153
154 CVDisplayLinkStart(link);
155 event->Wait();
156 CVDisplayLinkStop(link);
157 CVDisplayLinkRelease(link);
158 CFTimeInterval average = std::reduce(intervals->begin(), intervals->end()) / intervals->size();
159 CFTimeInterval max = *std::max_element(intervals->begin(), intervals->end());
160 CFTimeInterval min = *std::min_element(intervals->begin(), intervals->end());
161 NSLog(@"CVDisplayLink Interval: Average: %fs, Max: %fs, Min: %fs", average, max, min);
162 }
FlutterDisplayLink.h
TEST_F
TEST_F(FlutterDisplayLinkTest, ViewAddedToWindowFirst)
Definition: FlutterDisplayLinkTest.mm:42
FlutterRunLoop.h
FlutterDisplayLinkTest
Definition: FlutterDisplayLinkTest.mm:37
FlutterDisplayLinkTest::SetUp
void SetUp() override
Definition: FlutterDisplayLinkTest.mm:39
FlutterDisplayLink
Definition: FlutterDisplayLink.h:19
-[FlutterDisplayLink invalidate]
void invalidate()
Invalidates the display link.
Definition: FlutterDisplayLink.mm:293
FlutterDisplayLink::paused
BOOL paused
Pauses and resumes the display link.
Definition: FlutterDisplayLink.h:30
FlutterDisplayLink::delegate
id< FlutterDisplayLinkDelegate > delegate
Definition: FlutterDisplayLink.h:27
+[FlutterDisplayLink displayLinkWithView:]
instancetype displayLinkWithView:(NSView *view)
Definition: FlutterDisplayLink.mm:289
FlutterRunLoop
Definition: FlutterRunLoop.h:16
+[FlutterRunLoop ensureMainLoopInitialized]
void ensureMainLoopInitialized()
Definition: FlutterRunLoop.mm:111
-[FlutterRunLoop pollFlutterMessagesOnce]
void pollFlutterMessagesOnce()
Definition: FlutterRunLoop.mm:123
TestDisplayLinkDelegate
Definition: FlutterDisplayLinkTest.mm:14
TestDisplayLinkDelegate::_block
void(^ _block)(CFTimeInterval timestamp, CFTimeInterval targetTimestamp)
FlutterDisplayLinkDelegate-p
Definition: FlutterDisplayLink.h:6