Open Bug 1864047 Opened 2 years ago Updated 2 years ago

Substantial delay between first call to requestAnimationFrame() and callback

Categories

(Core :: Layout, defect)

Firefox 119
defect

Tracking

()

People

(Reporter: jbstrater, Assigned: dshin)

Details

User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0

Steps to reproduce:

Basic example:

  1. Open this jsfiddle: https://jsfiddle.net/sidewayss/rbt70q8z/
  2. Press the "Play" button
  3. Review the console messages: the first line shows a 5-8 frame delay, the second line shows a sub-single-frame duration (less than 16.67ms @ 60hz), realigning to a consistent frame rate relative to document.timeline.currentTime

Bonus points example:

  1. Open this version of the same fiddle: https://jsfiddle.net/sidewayss/rbt70q8z/7/
  2. Press and hold the "Play" button down for a few seconds
  3. Review the console messages: Note the way the click event value for document.timeline.currentTime is only a few milliseconds greater than the mousedown version, in spite of having held the mouse button down for several seconds

Expected results:

5-8 frames seems like an excessive delay. On Chrome the delay is zero. On Safari it is less than one frame. AFAICT, and based on feedback from Chrome developers and W3C specification authors, document.timeline.currentTime is always the same value as the rAF() callback timeStamp argument. The console messages in these fiddles confirm that.

The "hold down the mouse button" part of the issue might be a totally separate bug, but it was discovered using the original fiddle. Again, on Chrome and Safari there is no issue, and document.timeline.currentTime updates properly between the mousedown and click events.

I attempted to submit this as commentary on this existing, four-year-old issue, but there was no response there and it is likely an entirely different issue:
https://bugzilla.mozilla.org/show_bug.cgi?id=1606931

The Bugbug bot thinks this bug should belong to the 'Core::DOM: Core & HTML' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.

Component: Untriaged → DOM: Core & HTML
Product: Firefox → Core
Component: DOM: Core & HTML → Layout

In order to make it easier to test this on mobile devices, I have created new versions of the fiddles that display results in the HTML instead of the console.
Basic example: https://jsfiddle.net/sidewayss/rbt70q8z/9/
Hold down the mouse button example: https://jsfiddle.net/sidewayss/rbt70q8z/10/

Hm, so we run the tick on click with last timer tick timestamp, instead of the now timestamp, and that's the source of the "delay."
Clicking and holding the button stretches out the latency to as long as you hold the button, since the last tick is to render the clicked state of the button.

Severity: -- → S3
Status: UNCONFIRMED → NEW
Ever confirmed: true

@dshin - I looked at the code you link to, but there's a lot to dig into to understand nsRefreshDriver::Tick(). When you say "the now timestamp", you don't mean performance.now() do you? I assume not, because this issue is about document.timeline.currentTime, which AFAIK only updates once per screen refresh, or maybe additionally in the first calls to the requestAnimationFrame() callback. Maybe you could clarify that last detail for me as well, since these jsfiddle examples do show it updating faster than 60hz in the 2nd frame in particular, and the "delay" in the first frame is not a whole frame at 60hz either. Can you provide more detail here about the "last timer tick timestamp" vs. "the now timestamp"?

I realize that my questions won't help you fix this (should you decide to do so), but I would like to take this opportunity to educate myself on these details, if that's possible. Thanks!

DocumentTimeline.currentTime ends up here to get the timestamp, and since the refreshdriver is running, we look for the last time the screen had to be refreshed. The last time the screen had to be refreshed is when the button went from hover state to activated state, so zero effectively gets set there.

As for the whole frame issue - when we know we're not busy and know that the screen needs to be refreshed, we "catch up" by doing a refresh immediately. Check this profile based on the standalone version of the jsfiddle you uploaded - In Marker Chart, the first RefreshDriverTick after the click DOMEvent is closer to the next refresh.

Thanks for the information, link, and profile. It makes more sense to me now.

fyi - Chrome appears to do things a bit differently in that from the 2nd/3rd frame on the timeStamp values aren't aligned to the original .currentTIme along frame boundaries as in Firefox. In Firefox these fiddles display elapsed frame values that round to whole numbers at two decimal places. In Chrome they do not, though the time between frames is consistent. The difference is relative to the initial value of .currentTIme captured in the zero variable prior to calling requestAnimationFrame().

To confirm the fact that there isn't actually a multi-frame delay between the first call to requestAnimationFrame() and the first call to the callback, I adapted my basic example fiddle here: https://jsfiddle.net/sidewayss/rbt70q8z/11/

Based on the performance.now() values, you can see that at most a few milliseconds elapse during that time. The appearance of a delay is due to the way document.timeline.currentTime is set, as described by @dshin above. The only issue is with the updating of document.timeline.curentTime.

Assignee: nobody → dshin

Note that bug 1865637 tweaks a bit that code (not sure it matters for this tho).

You need to log in before you can comment on or make changes to this bug.