Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
7#import <AppKit/AppKit.h>
8#include <numeric>
9
10#include "flutter/fml/synchronization/waitable_event.h"
11#include "flutter/testing/testing.h"
12
14 void (^_block)(CFTimeInterval timestamp, CFTimeInterval targetTimestamp);
15}
16
17- (instancetype)initWithBlock:(void (^)(CFTimeInterval timestamp,
18 CFTimeInterval targetTimestamp))block;
19
20@end
21
22@implementation TestDisplayLinkDelegate
23- (instancetype)initWithBlock:(void (^__strong)(CFTimeInterval, CFTimeInterval))block {
24 if (self = [super init]) {
25 _block = block;
26 }
27 return self;
28}
29
30- (void)onDisplayLink:(CFTimeInterval)timestamp targetTimestamp:(CFTimeInterval)targetTimestamp {
31 _block(timestamp, targetTimestamp);
32}
33
34@end
35
36TEST(FlutterDisplayLinkTest, ViewAddedToWindowFirst) {
37 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
38 styleMask:NSWindowStyleMaskTitled
39 backing:NSBackingStoreNonretained
40 defer:NO];
41 NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
42 [window setContentView:view];
43
44 auto event = std::make_shared<fml::AutoResetWaitableEvent>();
45
47 initWithBlock:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp) {
48 event->Signal();
49 }];
50
52 displayLink.delegate = delegate;
53 displayLink.paused = NO;
54
55 event->Wait();
56
57 [displayLink invalidate];
58}
59
60TEST(FlutterDisplayLinkTest, ViewAddedToWindowLater) {
61 NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
62
63 auto event = std::make_shared<fml::AutoResetWaitableEvent>();
64
66 initWithBlock:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp) {
67 event->Signal();
68 }];
69
71 displayLink.delegate = delegate;
72 displayLink.paused = NO;
73
74 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
75 styleMask:NSWindowStyleMaskTitled
76 backing:NSBackingStoreNonretained
77 defer:NO];
78 [window setContentView:view];
79
80 event->Wait();
81
82 [displayLink invalidate];
83}
84
85TEST(FlutterDisplayLinkTest, ViewRemovedFromWindow) {
86 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
87 styleMask:NSWindowStyleMaskTitled
88 backing:NSBackingStoreNonretained
89 defer:NO];
90 NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
91 [window setContentView:view];
92
93 auto event = std::make_shared<fml::AutoResetWaitableEvent>();
94
96 initWithBlock:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp) {
97 event->Signal();
98 }];
99
101 displayLink.delegate = delegate;
102 displayLink.paused = NO;
103
104 event->Wait();
105 displayLink.paused = YES;
106
107 event->Reset();
108
109 displayLink.paused = NO;
110
111 [window setContentView:nil];
112
113 EXPECT_TRUE(event->WaitWithTimeout(fml::TimeDelta::FromMilliseconds(100)));
114 EXPECT_FALSE(event->IsSignaledForTest());
115
116 [displayLink invalidate];
117}
118
119TEST(FlutterDisplayLinkTest, WorkaroundForFB13482573) {
120 NSWindow* window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
121 styleMask:NSWindowStyleMaskTitled
122 backing:NSBackingStoreNonretained
123 defer:NO];
124 NSView* view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)];
125 [window setContentView:view];
126
127 auto event = std::make_shared<fml::AutoResetWaitableEvent>();
128
130 initWithBlock:^(CFTimeInterval timestamp, CFTimeInterval targetTimestamp) {
131 event->Signal();
132 }];
133
135 displayLink.delegate = delegate;
136 displayLink.paused = NO;
137
138 event->Wait();
139 displayLink.paused = YES;
140
141 event->Reset();
142 [NSThread detachNewThreadWithBlock:^{
143 // Here pthread_self() will be same as pthread_self inside first invocation of
144 // display link callback, causing CVDisplayLinkStart to return error.
145 displayLink.paused = NO;
146 }];
147
148 event->Wait();
149
150 [displayLink invalidate];
151}
152
153TEST(FlutterDisplayLinkTest, CVDisplayLinkInterval) {
154 CVDisplayLinkRef link;
155 CVDisplayLinkCreateWithCGDisplay(CGMainDisplayID(), &link);
156 __block CFTimeInterval last = 0;
157 auto intervals = std::make_shared<std::vector<CFTimeInterval>>();
158 auto event = std::make_shared<fml::AutoResetWaitableEvent>();
159 CVDisplayLinkSetOutputHandler(
160 link, ^(CVDisplayLinkRef displayLink, const CVTimeStamp* inNow,
161 const CVTimeStamp* inOutputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut) {
162 if (last != 0) {
163 intervals->push_back(CACurrentMediaTime() - last);
164 }
165 last = CACurrentMediaTime();
166 if (intervals->size() == 10) {
167 event->Signal();
168 }
169 return 0;
170 });
171
172 CVDisplayLinkStart(link);
173 event->Wait();
174 CVDisplayLinkStop(link);
175 CVDisplayLinkRelease(link);
176 CFTimeInterval average = std::reduce(intervals->begin(), intervals->end()) / intervals->size();
177 CFTimeInterval max = *std::max_element(intervals->begin(), intervals->end());
178 CFTimeInterval min = *std::min_element(intervals->begin(), intervals->end());
179 NSLog(@"CVDisplayLink Interval: Average: %fs, Max: %fs, Min: %fs", average, max, min);
180}
#define TEST(S, s, D, expected)
static constexpr TimeDelta FromMilliseconds(int64_t millis)
Definition time_delta.h:46
GLFWwindow * window
Definition main.cc:45
FlKeyEvent * event
static float max(float r, float g, float b)
Definition hsl.cpp:49
static float min(float r, float g, float b)
Definition hsl.cpp:48
void(^ _block)(CFTimeInterval timestamp, CFTimeInterval targetTimestamp)
#define EXPECT_TRUE(handle)
Definition unit_test.h:685