Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change requestAnimationFrame flush condition #6442

Merged

Conversation

bartlomiejbloniarz
Copy link
Contributor

@bartlomiejbloniarz bartlomiejbloniarz commented Aug 22, 2024

Summary

Currently we schedulerAF flush when the first callback is added to the list. However the flush method can also be called by an event, meaning that sometimes we have a flush scheduled to run on a given frame, but the callbacks array is empty. If then, another callback is requested, the array will contain 1 element, triggering another flush request (even though one is already scheduled). To prevent this, from causing countless requests on a singe frame we check the frame timestamp and abort if it's repeated.

This approach unfortunately causes some problems when video is playing in the app. On iPhone devices sometimes the displayLink can fire its callback twice in a single frame (with the same timestamp). This leads to us cancelling the rAF flush, which means that until an event triggers a flush, none updates from reanimated will come through.

This PR changes the way we request a flush. Instead of checking the callbacks array size, we instead remember whether a flush was requested and request a new one only when there was no request. This prevents us from requesting unnecessary flushes when an event has caused the callbacks array to be emptied, while also allowing for repeated frame timestamps.

closes #6371

Test plan

Check for regressions in the example app and in this example:
https://gist.github.com/kmagiera/b2df85f9512951f5e6ceee7bc569f5f1

Copy link
Member

@kmagiera kmagiera left a comment

Choose a reason for hiding this comment

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

This looks good. The only thing I'm wondering now is that when duplicated rAFs come at the same timestamp, we will run all the mappers twice with the same input, which may not be as efficient as needed, especially given it happens for example when video is being played (relatively heavy task as well). Normally, I wouldn't be concerned about running mappers twice in a frame from time to time, but it it happens continuously for the whole duration of the video, I'd love if we try to measure the consequences here and at least add a comment about that in the PR description.

@bartlomiejbloniarz
Copy link
Contributor Author

In my testing it wasn't a continuous issue, it only happened from time to time. Sometimes I had to try for a few minutes to get it to break.

Copy link
Collaborator

@tjzel tjzel left a comment

Choose a reason for hiding this comment

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

:shipit:

@bartlomiejbloniarz bartlomiejbloniarz added this pull request to the merge queue Aug 28, 2024
Merged via the queue into main with commit 6933d14 Aug 28, 2024
9 checks passed
@bartlomiejbloniarz bartlomiejbloniarz deleted the @bartlomiejbloniarz/change-raf-flush-condition branch August 28, 2024 10:32
tjzel pushed a commit that referenced this pull request Aug 28, 2024
## Summary
Currently we schedule`rAF` flush when the first callback is added to the
list. However the flush method can also be called by an event, meaning
that sometimes we have a flush scheduled to run on a given frame, but
the callbacks array is empty. If then, another callback is requested,
the array will contain 1 element, triggering another flush request (even
though one is already scheduled). To prevent this, from causing
countless requests on a singe frame we check the frame timestamp and
abort if it's repeated.

This approach unfortunately causes some problems when video is playing
in the app. On iPhone devices sometimes the displayLink can fire its
callback twice in a single frame (with the same timestamp). This leads
to us cancelling the `rAF` flush, which means that until an event
triggers a flush, none updates from reanimated will come through.

This PR changes the way we request a flush. Instead of checking the
callbacks array size, we instead remember whether a flush was requested
and request a new one only when there was no request. This prevents us
from requesting unnecessary flushes when an event has caused the
callbacks array to be emptied, while also allowing for repeated frame
timestamps.

closes #6371 

## Test plan

Check for regressions in the example app and in this example:
https://gist.github.com/kmagiera/b2df85f9512951f5e6ceee7bc569f5f1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Reanimated Stops Working Completely on iOS
4 participants