Bug 261031 - Visible jank in 60fps animation containing 2 alternating frames, no matter of approach taken
Summary: Visible jank in 60fps animation containing 2 alternating frames, no matter of...
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: Animations (show other bugs)
Version: Safari 16
Hardware: Mac (Intel) macOS 13
: P2 Normal
Assignee: Nobody
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2023-09-01 06:27 PDT by Wojciech Czechowski
Modified: 2023-12-05 02:25 PST (History)
7 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Wojciech Czechowski 2023-09-01 06:27:43 PDT
I tried to create simple flickering animation that contains 2 alternating frames. No matter of taken approach (drawing on canvas with / without web worker, pure CSS, Web Animation API), browser is unable to run it smoothly, without visible jank. 

What’s interesting, I guess, is that Safari is able to play the embedded pre-prepared video of such animation smoothly.

Prototype page that shows the issue can be found here: https://dev.sfio.xyz/flickering-animation-bugs

The page contains all approches side-by-side with respective links to codepens, so that the code can be reviewed. 

I suppose there is some issue with browser’s rendering engine.
Comment 1 Alexey Proskuryakov 2023-09-03 15:05:37 PDT
FWIW, while Chrome doesn't report any slow frames, I'm not sure if the test is any better visually there than in Safari (but also, not really sure what to expect as "correct behavior" in this case.
Comment 2 Wojciech Czechowski 2023-09-03 22:57:01 PDT
Correct behaviour is the one seen on the video example in Safari - animation should play smoothly, which - for some unknown reason - is not happening. There are repeated frames from time to time, event thought it is not reported by the browser, as you noticed. 

Chrome (and Firefox) have the same issue (which I also reported). What's more, they even struggle to play the video smoothly, so you I think you won't find any answers there... :]
Comment 3 Simon Fraser (smfr) 2023-09-05 10:51:04 PDT
You have to be really careful here; adding log elements is going to block the main thread, and the longer the log list gets, the longer that will take. Also, the different subtests may interfere with each other, so I'd suggest moving each into its own document.

That are many things going on in the browser that may cause dropped frames here (e.g. JS garbage collection); browsers really aren't designed as realtime OSes, so getting to zero frame drops would be really hard.
Comment 4 Wojciech Czechowski 2023-09-07 00:59:12 PDT
Did you carefully check the provided website, Simon? There are links that lead to separate codepens for each approach. You can easily remove logging part there, but I assure you, that it is not the problem here... ;) 

By the way - blocking the main thread shouldn't bother the web worker. That's why I added "block main thread" button in there - to prove, that dropped frames are not caused by it being to busy...

What's more -> for js approaches I intentionally draw number of miliseconds between current and previous frame directly on the canvases. If you look carefully, you can see, that "dropped frames effect" ( jank ) is visible even if there is less than 17ms between frames, which means, that it is not there because js can't handle calculations in time needed to accomplish 60fps.

I am totally aware, that it is hard to get zero frame drops and that there are many things going on in the browser, that may cause jank. That's why I tried few different approaches... 

Why is it happening even for embedded video? Why simple CSS animation is also struggling to render it properly? Why I can see this jank, even if each frame of requestAnimationFrame takes ~16.66ms, which is exactly as much as needed to get smooth 60fps? 

Sorry, but "Many things that may cause dropped frames" is to broad answer for my questions.
Comment 5 Wojciech Czechowski 2023-09-07 01:04:11 PDT
I can't edit unfortunately, so I'll ad this as an errata: 

"Why is it happening even for embedded video?" -> this one doesn't apply to safari of course, so don't bother to answer it ;)
Comment 6 Wojciech Czechowski 2023-09-07 02:06:51 PDT
OK, I prepared separate page for pure css animation: https://dev.sfio.xyz/flickering-animation-bugs/pureCSS

There is no JavaScript at all. Just simple CSS animation of two squares that are swapping position in 60fps using transform: translate. 

Still not smooth at all, any ideas what is the reason, Simon?
Comment 7 Radar WebKit Bug Importer 2023-09-08 06:28:14 PDT
<rdar://problem/115169833>
Comment 8 Wojciech Czechowski 2023-12-05 02:25:34 PST
I recently conducted some tests to assess the feasibility of this type of animation. I would like to share the results with you, as it may help identify issues with the browser.

I prepared six different repositories, each containing a simple app. The only functionality of these apps is to flicker between two colored rectangles at 60fps. These apps are written in various technologies and for different platforms. Each repository includes a readme file with building instructions, allowing you to review both the source code and the working app. The links to the repositories are provided below. I can't wait for you to check them out and draw some conclusions.

Spoiler alert: The apps written in C++ with the SDL2 library (for all platforms), Kotlin, and SwiftUI work smoothly with the animation, without any visible glitches. However, the one written in Flutter (for all platforms) produces results very similar to those observed in the browser...

So, in principle, achieving jank-free animations on all platforms is possible. The introduction of jank seems to be located in the browser rendering implementation.

Mentioned links: 

1. ColourFlicker written in Kotlin [ for android ]: https://github.com/WojciechCzechowski-SmartFrame/ColourFlicker_Kotlin_android
2. ColourFlicker written in SwiftUI [ for iOS ]: https://github.com/WojciechCzechowski-SmartFrame/ColourFlicker_SwiftUI_iOS
3. ColourFlicker written in C++/SDL2 [ for windows ]:  https://github.com/WojciechCzechowski-SmartFrame/ColourFlicker_SDL2_windows
4. ColourFlicker written in C++/SDL2 [ for macOS ]: https://github.com/WojciechCzechowski-SmartFrame/ColourFlicker_SDL2_macOS
5. ColourFlicker written in C++/SDL2 [ for linux ]: https://github.com/WojciechCzechowski-SmartFrame/ColourFlicker_SDL2_linux

6. ColourFlicker written in Dart/Flutter [ for all platforms ]: https://github.com/WojciechCzechowski-SmartFrame/ColourFlicker_Flutter_all-platforms