5#import "flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h"
9#include <Foundation/Foundation.h>
10#include <UIKit/UIKit.h>
11#include <mach/mach_time.h>
13#include "flutter/common/task_runners.h"
14#include "flutter/fml/logging.h"
15#include "flutter/fml/memory/task_runner_checker.h"
16#include "flutter/fml/trace_event.h"
17#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h"
32 auto callback = [this](std::unique_ptr<flutter::FrameTimingsRecorder> recorder) {
37 client_ = [[
VSyncClient alloc] initWithTaskRunner:task_runners_.GetUITaskRunner()
51 max_refresh_rate_ = new_max_refresh_rate;
69- (instancetype)initWithTaskRunner:(
fml::RefPtr<
fml::TaskRunner>)task_runner
75 _allowPauseAfterVsync = YES;
77 _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)];
80 [
self setMaxRefreshRate:DisplayLinkManager.displayRefreshRate];
84 task_runner->PostTask([localDisplayLink]() {
85 [localDisplayLink addToRunLoop:NSRunLoop.currentRunLoop forMode:NSRunLoopCommonModes];
92- (void)setMaxRefreshRate:(
double)refreshRate {
96 double maxFrameRate = fmax(refreshRate, 60);
97 double minFrameRate = fmax(maxFrameRate / 2, 60);
98 if (@available(iOS 15.0, *)) {
100 CAFrameRateRangeMake(minFrameRate, maxFrameRate, maxFrameRate);
114- (void)onDisplayLink:(CADisplayLink*)link {
115 CFTimeInterval delay = CACurrentMediaTime() -
link.timestamp;
125 std::unique_ptr<flutter::FrameTimingsRecorder> recorder =
126 std::make_unique<flutter::FrameTimingsRecorder>();
128 _refreshRate =
round(1 / (frame_target_time - frame_start_time).ToSecondsF());
130 recorder->RecordVsync(frame_start_time, frame_target_time);
131 if (_allowPauseAfterVsync) {
134 _callback(std::move(recorder));
138 [_displayLink invalidate];
142- (CADisplayLink*)getDisplayLink {
151 CADisplayLink* displayLink = [CADisplayLink displayLinkWithTarget:[[[
self class] alloc] init]
152 selector:@selector(onDisplayLink:)];
153 displayLink.paused = YES;
154 auto preferredFPS = displayLink.preferredFramesPerSecond;
161 if (preferredFPS != 0) {
165 return UIScreen.mainScreen.maximumFramesPerSecond;
168- (void)onDisplayLink:(CADisplayLink*)link {
173 return [[NSBundle.mainBundle objectForInfoDictionaryKey:@"CADisableMinimumFrameDurationOnPhone"]
static void round(SkPoint *p)
~VsyncWaiterIOS() override
double GetRefreshRate() const override
void AwaitVSync() override
VsyncWaiterIOS(const flutter::TaskRunners &task_runners)
std::function< void(std::unique_ptr< FrameTimingsRecorder >)> Callback
void FireCallback(fml::TimePoint frame_start_time, fml::TimePoint frame_target_time, bool pause_secondary_tasks=true)
constexpr int64_t ToMicroseconds() const
TimeDelta ToEpochDelta() const
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
BOOL maxRefreshRateEnabledOnIPhone
double displayRefreshRate
The display refresh rate used for reporting purposes. The engine does not care about this for frame s...
void setMaxRefreshRate:(double refreshRate)
void invalidate()
Call invalidate before releasing this object to remove from runloops.
def link(from_root, to_root)
std::function< void(MTLRenderPipelineDescriptor *)> Callback
#define TRACE_EVENT2_INT(category_group, name, arg1_name, arg1_val, arg2_name, arg2_val)
CADisplayLink * _displayLink
static const double kRefreshRateDiffToIgnore