Skip to content

WIP: Reduce touch to present latency on iOS - #191368

Draft
knopp wants to merge 2 commits into
flutter:masterfrom
knopp:vsync2
Draft

knopp wants to merge 2 commits into
flutter:masterfrom
knopp:vsync2

Conversation

@knopp

@knopp knopp commented Aug 19, 2026 •

Copy link
Copy Markdown
Member

This is a reasonably minimal change required to reduce the touch to present latency on iOS by one frame.

  • Replaces SmoothPointerDataDispatcher with DefaultPointerDataDispatcher.
  • Ensures that the path from touchesMoved all the way to VSyncWaiter::AwaitVSync is completely synchronous without scheduling unnecessary event loop turns. This is required so that CADisplayLink callback is always called after AwaitVSync. Other embedders will likely benefit from this change too.
  • Modifies vsync_waiter_ios to not waste time when scheduling the first frame and does not pause the display link after each tick.

With this PR, this is the flow for each frame during tracking on iOS (and other platform with merged threads):

                        +-  touchesMoved:
                        |        \/
synchronous operation --+   pointer processing in framework requests new frame
 (same runloop turn)    |        \/
                        +-  vsync request
                                 \/
                            display link callback

Note that UIKit phases are well defined and event dispatch is guaranteed to come before display link callback.

List which issues are fixed by this PR. You must list at least one issue. An issue is not required if the PR fixes something trivial like a typo.

If you had to change anything in the flutter/tests repo, include a link to the migration guide as per the breaking change policy.

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

@knopp
knopp requested a review from a team as a code owner August 19, 2026 17:10
@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label Aug 19, 2026
@flutter-dashboard

Copy link
Copy Markdown

It looks like this pull request may not have tests. Please make sure to add tests or get an explicit test exemption before merging.

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. If you believe this PR qualifies for a test exemption, contact "@test-exemption-reviewer" in the #hackers channel in Discord (don't just cc them here, they won't see it!). The test exemption team is a small volunteer group, so all reviewers should feel empowered to ask for tests, without delegating that responsibility entirely to the test exemption group.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request simplifies frame scheduling in the animator, enables synchronous pointer event dispatching, switches to the default pointer data dispatcher on iOS, and introduces vsync state tracking in the iOS vsync waiter. Feedback on these changes identifies critical multithreading issues in the iOS vsync waiter, specifically pointing out data races and potential deadlocks due to unsynchronized access to waiting_for_vsync_ across the UI and Platform threads, as well as potential animation stutter from zero-duration frame budgets.

FlutterVSyncClient* client_;
FlutterDisplayLinkManager* display_link_manager_;
double max_refresh_rate_;
bool waiting_for_vsync_ = false;

This comment was marked as low quality.

@knopp knopp Aug 19, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UI thread and platform thread are the same thing. Please stop.

Comment on lines +23 to +28
if (!waiting_for_vsync_) {
[client_ pause];
return;
}
waiting_for_vsync_ = false;

This comment was marked as off-topic.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no mutex and we don't need to do any of this.

Comment on lines +70 to +75
if (client_.displayLink.paused) {
[client_ await];
FireCallback(fml::TimePoint::Now(), fml::TimePoint::Now(), false);
} else {
waiting_for_vsync_ = true;
}

This comment was marked as off-topic.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope. It's one thread. Please gemini, try to keep up.

}
self->AwaitVSync();
});
AwaitVSync();

@knopp knopp Aug 19, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really don't see any point in increasing latency to schedule await for vsync, which should be a very cheap operation, in a separate run loop turn. Especially bad idea with the recent discovery that iOS scheduler really like to put Flutter apps on e-cores.


if (client_.displayLink.paused) {
[client_ await];
FireCallback(fml::TimePoint::Now(), fml::TimePoint::Now(), false);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arguably this is called from AwaitForVsync, and we might consider scheduling this in separate run loop turn to mimic displaylink callback for consistency.

@github-actions github-actions Bot added platform-ios iOS applications specifically engine flutter/engine related. See also e: labels. team-ios Owned by iOS platform team labels Aug 19, 2026
@knopp

knopp commented Aug 19, 2026

Copy link
Copy Markdown
Member Author

Note, this will reduce the latency by 1 frame, but we're sadly still one frame behind UIKit, because when touch events are processed, any modification to layer tree after initial CA commit (which happens right after display link callback) will be postponed until next frame. We're rendering the content asynchronously and are not currently able to set layer content before the CA commit. I do have couple of ideas I want to try here though.

@flutter-dashboard

Copy link
Copy Markdown

This pull request executed golden file tests, but it has not been updated in a while (20+ days). Test results from Gold expire after as many days, so this pull request will need to be updated with a fresh commit in order to get results from Gold.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

@knopp
knopp marked this pull request as draft September 10, 2026 21:50
@flutter-dashboard

Copy link
Copy Markdown

This pull request has been changed to a draft. The currently pending flutter-gold status will not be able to resolve until a new commit is pushed or the change is marked ready for review again.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD engine flutter/engine related. See also e: labels. platform-ios iOS applications specifically team-ios Owned by iOS platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant