This repository was archived by the owner on Feb 25, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6k
Migrate vsync_waiter_ios to ARC #52104
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,10 @@ | |
#include "flutter/fml/memory/task_runner_checker.h" | ||
#include "flutter/fml/trace_event.h" | ||
|
||
@interface VSyncClient () | ||
@property(nonatomic, assign, readonly) double refreshRate; | ||
@end | ||
|
||
// When calculating refresh rate diffrence, anything within 0.1 fps is ignored. | ||
const static double kRefreshRateDiffToIgnore = 0.1; | ||
|
||
|
@@ -27,63 +31,55 @@ | |
const fml::TimePoint target_time = recorder->GetVsyncTargetTime(); | ||
FireCallback(start_time, target_time, true); | ||
}; | ||
client_ = | ||
fml::scoped_nsobject{[[VSyncClient alloc] initWithTaskRunner:task_runners_.GetUITaskRunner() | ||
callback:callback]}; | ||
max_refresh_rate_ = [DisplayLinkManager displayRefreshRate]; | ||
client_ = [[VSyncClient alloc] initWithTaskRunner:task_runners_.GetUITaskRunner() | ||
callback:callback]; | ||
max_refresh_rate_ = DisplayLinkManager.displayRefreshRate; | ||
} | ||
|
||
VsyncWaiterIOS::~VsyncWaiterIOS() { | ||
// This way, we will get no more callbacks from the display link that holds a weak (non-nilling) | ||
// reference to this C++ object. | ||
[client_.get() invalidate]; | ||
[client_ invalidate]; | ||
} | ||
|
||
void VsyncWaiterIOS::AwaitVSync() { | ||
double new_max_refresh_rate = [DisplayLinkManager displayRefreshRate]; | ||
double new_max_refresh_rate = DisplayLinkManager.displayRefreshRate; | ||
if (fabs(new_max_refresh_rate - max_refresh_rate_) > kRefreshRateDiffToIgnore) { | ||
max_refresh_rate_ = new_max_refresh_rate; | ||
[client_.get() setMaxRefreshRate:max_refresh_rate_]; | ||
[client_ setMaxRefreshRate:max_refresh_rate_]; | ||
} | ||
[client_.get() await]; | ||
[client_ await]; | ||
} | ||
|
||
// |VariableRefreshRateReporter| | ||
double VsyncWaiterIOS::GetRefreshRate() const { | ||
return [client_.get() getRefreshRate]; | ||
} | ||
|
||
fml::scoped_nsobject<VSyncClient> VsyncWaiterIOS::GetVsyncClient() const { | ||
return client_; | ||
return client_.refreshRate; | ||
} | ||
|
||
} // namespace flutter | ||
|
||
@implementation VSyncClient { | ||
flutter::VsyncWaiter::Callback callback_; | ||
fml::scoped_nsobject<CADisplayLink> display_link_; | ||
double current_refresh_rate_; | ||
flutter::VsyncWaiter::Callback _callback; | ||
CADisplayLink* _displayLink; | ||
} | ||
|
||
- (instancetype)initWithTaskRunner:(fml::RefPtr<fml::TaskRunner>)task_runner | ||
callback:(flutter::VsyncWaiter::Callback)callback { | ||
self = [super init]; | ||
|
||
if (self) { | ||
current_refresh_rate_ = [DisplayLinkManager displayRefreshRate]; | ||
_refreshRate = DisplayLinkManager.displayRefreshRate; | ||
_allowPauseAfterVsync = YES; | ||
callback_ = std::move(callback); | ||
display_link_ = fml::scoped_nsobject<CADisplayLink> { | ||
[[CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)] retain] | ||
}; | ||
display_link_.get().paused = YES; | ||
|
||
[self setMaxRefreshRate:[DisplayLinkManager displayRefreshRate]]; | ||
|
||
task_runner->PostTask([client = [self retain]]() { | ||
[client->display_link_.get() addToRunLoop:[NSRunLoop currentRunLoop] | ||
forMode:NSRunLoopCommonModes]; | ||
[client release]; | ||
_callback = std::move(callback); | ||
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)]; | ||
_displayLink.paused = YES; | ||
|
||
[self setMaxRefreshRate:DisplayLinkManager.displayRefreshRate]; | ||
|
||
// Strongly retain the the captured link until it is added to the runloop. | ||
CADisplayLink* localDisplayLink = _displayLink; | ||
task_runner->PostTask([localDisplayLink]() { | ||
[localDisplayLink addToRunLoop:NSRunLoop.currentRunLoop forMode:NSRunLoopCommonModes]; | ||
}); | ||
} | ||
|
||
|
@@ -97,19 +93,19 @@ - (void)setMaxRefreshRate:(double)refreshRate { | |
double maxFrameRate = fmax(refreshRate, 60); | ||
double minFrameRate = fmax(maxFrameRate / 2, 60); | ||
if (@available(iOS 15.0, *)) { | ||
display_link_.get().preferredFrameRateRange = | ||
_displayLink.preferredFrameRateRange = | ||
CAFrameRateRangeMake(minFrameRate, maxFrameRate, maxFrameRate); | ||
} else { | ||
display_link_.get().preferredFramesPerSecond = maxFrameRate; | ||
_displayLink.preferredFramesPerSecond = maxFrameRate; | ||
} | ||
} | ||
|
||
- (void)await { | ||
display_link_.get().paused = NO; | ||
_displayLink.paused = NO; | ||
} | ||
|
||
- (void)pause { | ||
display_link_.get().paused = YES; | ||
_displayLink.paused = YES; | ||
} | ||
|
||
- (void)onDisplayLink:(CADisplayLink*)link { | ||
|
@@ -126,44 +122,33 @@ - (void)onDisplayLink:(CADisplayLink*)link { | |
std::unique_ptr<flutter::FrameTimingsRecorder> recorder = | ||
std::make_unique<flutter::FrameTimingsRecorder>(); | ||
|
||
current_refresh_rate_ = round(1 / (frame_target_time - frame_start_time).ToSecondsF()); | ||
_refreshRate = round(1 / (frame_target_time - frame_start_time).ToSecondsF()); | ||
|
||
recorder->RecordVsync(frame_start_time, frame_target_time); | ||
if (_allowPauseAfterVsync) { | ||
display_link_.get().paused = YES; | ||
link.paused = YES; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use |
||
} | ||
callback_(std::move(recorder)); | ||
_callback(std::move(recorder)); | ||
} | ||
|
||
- (void)invalidate { | ||
[display_link_.get() invalidate]; | ||
} | ||
|
||
- (void)dealloc { | ||
[self invalidate]; | ||
|
||
[super dealloc]; | ||
} | ||
|
||
- (double)getRefreshRate { | ||
return current_refresh_rate_; | ||
[_displayLink invalidate]; | ||
_displayLink = nil; // Break retain cycle. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The test I wrote to validate the display link is released when |
||
} | ||
|
||
- (CADisplayLink*)getDisplayLink { | ||
return display_link_.get(); | ||
return _displayLink; | ||
} | ||
|
||
@end | ||
|
||
@implementation DisplayLinkManager | ||
|
||
+ (double)displayRefreshRate { | ||
fml::scoped_nsobject<CADisplayLink> display_link = fml::scoped_nsobject<CADisplayLink> { | ||
[[CADisplayLink displayLinkWithTarget:[[[DisplayLinkManager alloc] init] autorelease] | ||
selector:@selector(onDisplayLink:)] retain] | ||
}; | ||
display_link.get().paused = YES; | ||
auto preferredFPS = display_link.get().preferredFramesPerSecond; | ||
CADisplayLink* displayLink = [CADisplayLink displayLinkWithTarget:[[[self class] alloc] init] | ||
selector:@selector(onDisplayLink:)]; | ||
displayLink.paused = YES; | ||
auto preferredFPS = displayLink.preferredFramesPerSecond; | ||
|
||
// From Docs: | ||
// The default value for preferredFramesPerSecond is 0. When this value is 0, the preferred | ||
|
@@ -174,15 +159,15 @@ + (double)displayRefreshRate { | |
return preferredFPS; | ||
} | ||
|
||
return [UIScreen mainScreen].maximumFramesPerSecond; | ||
return UIScreen.mainScreen.maximumFramesPerSecond; | ||
} | ||
|
||
- (void)onDisplayLink:(CADisplayLink*)link { | ||
// no-op. | ||
} | ||
|
||
+ (BOOL)maxRefreshRateEnabledOnIPhone { | ||
return [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CADisableMinimumFrameDurationOnPhone"] | ||
return [[NSBundle.mainBundle objectForInfoDictionaryKey:@"CADisableMinimumFrameDurationOnPhone"] | ||
boolValue]; | ||
} | ||
|
||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't currently pass on main with the current code.