1#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterVSyncWaiter.h"
2#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDisplayLink.h"
4#include "flutter/fml/logging.h"
9#if (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_PROFILE)
10#define VSYNC_TRACING_ENABLED 1
13#if VSYNC_TRACING_ENABLED
14#include <OSLog/OSLog.h>
18#define TRACE_VSYNC(event_type, baton) \
20 os_log_t log = os_log_create("FlutterVSync", "PointsOfInterest"); \
21 os_signpost_event_emit(log, OS_SIGNPOST_ID_EXCLUSIVE, event_type, "baton %lx", baton); \
24#define TRACE_VSYNC(event_type, baton) \
37 std::optional<std::uintptr_t> _pendingBaton;
39 void (^
_block)(CFTimeInterval, CFTimeInterval, uintptr_t);
46 block:(
void (^)(CFTimeInterval timestamp,
47 CFTimeInterval targetTimestamp,
48 uintptr_t baton))block {
63- (void)processDisplayLink:(CFTimeInterval)timestamp
64 targetTimestamp:(CFTimeInterval)targetTimestamp {
72 CFTimeInterval minStart = targetTimestamp -
_displayLink.nominalOutputRefreshPeriod;
73 CFTimeInterval current = CACurrentMediaTime();
76 TRACE_VSYNC(
"DisplayLinkCallback-Original", _pendingBaton.value_or(0));
78 NSTimer* timer = [NSTimer
79 timerWithTimeInterval:remaining
81 block:^(NSTimer* _Nonnull timer) {
82 if (!_pendingBaton.has_value()) {
83 TRACE_VSYNC("DisplayLinkPaused", size_t(0));
84 _displayLink.paused = YES;
87 TRACE_VSYNC("DisplayLinkCallback-Delayed", _pendingBaton.value_or(0));
88 _block(minStart, targetTimestamp, *_pendingBaton);
89 _pendingBaton = std::nullopt;
91 [_runLoop addTimer:timer forMode:NSRunLoopCommonModes];
95- (void)onDisplayLink:(CFTimeInterval)timestamp targetTimestamp:(CFTimeInterval)targetTimestamp {
102 [_runLoop performBlock:^{
103 [
self processDisplayLink:timestamp targetTimestamp:targetTimestamp];
110- (void)waitForVSync:(uintptr_t)baton {
116 [[NSRunLoop currentRunLoop] performBlock:^{
117 CFTimeInterval now = CACurrentMediaTime();
118 _block(now, now, baton);
124 @
synchronized(
self) {
126 _runLoop = [NSRunLoop currentRunLoop];
131 if (_pendingBaton.has_value()) {
132 FML_LOG(WARNING) <<
"Engine requested vsync while another was pending";
133 _block(0, 0, *_pendingBaton);
134 _pendingBaton = std::nullopt;
137 TRACE_VSYNC(
"VSyncRequest", _pendingBaton.value_or(0));
149 CFTimeInterval
start = CACurrentMediaTime();
152 CFTimeInterval delay = 0;
156 CFTimeInterval now =
start;
157 start = now - (fmod(now, tick_interval)) + phase;
159 start += tick_interval;
164 NSTimer* timer = [NSTimer timerWithTimeInterval:delay
166 block:^(NSTimer* timer) {
167 CFTimeInterval targetTimestamp =
168 start + tick_interval;
169 TRACE_VSYNC("SynthesizedInitialVSync", baton);
170 _block(start, targetTimestamp, baton);
172 [_runLoop addTimer:timer forMode:NSRunLoopCommonModes];
175 _pendingBaton = baton;
180 if (_pendingBaton.has_value()) {
181 FML_LOG(WARNING) <<
"Deallocating FlutterVSyncWaiter with a pending vsync";
183 [_displayLink invalidate];
FlutterDisplayLink * _displayLink
static const CFTimeInterval kTimerLatencyCompensation
#define TRACE_VSYNC(event_type, baton)
CFTimeInterval _lastTargetTimestamp
void(^ _block)(CFTimeInterval, CFTimeInterval, uintptr_t)
#define FML_LOG(severity)
#define FML_DCHECK(condition)
static float max(float r, float g, float b)
CFTimeInterval nominalOutputRefreshPeriod
BOOL paused
Pauses and resumes the display link. May be called from any thread.
id< FlutterDisplayLinkDelegate > delegate