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

requestAnimationFrame is called ~1500 times per second #7782

Closed
paulrouget opened this issue Sep 29, 2015 · 28 comments
Closed

requestAnimationFrame is called ~1500 times per second #7782

paulrouget opened this issue Sep 29, 2015 · 28 comments

Comments

@paulrouget
Copy link
Contributor

@paulrouget paulrouget commented Sep 29, 2015

Which is a little bit too much :)

<script>
  var count = 0;
  function step() {
    count++;
    requestAnimationFrame(step);
  }

  setInterval(function() {
    document.body.textContent = count + "FPS";
    count = 0;
  }, 1000);

  step();
</script>
@glennw
Copy link
Member

@glennw glennw commented Sep 29, 2015

Yep - I ran across this yesterday. The callback is triggered whenever the compositor runs, which is as fast as possible when animations are running (which is also wrong). Instead, it should only trigger the callback after an entire paint completes for the relevant pipeline. This is a little bit tricky, since it needs to check the epoch for each layer that is painted for the pipeline in question.

@Yoric
Copy link
Contributor

@Yoric Yoric commented Sep 29, 2015

@glennw I'd like to work on this, if you can give me a hand.

I am trying to understand to follow the chain that triggers the callback. As I understand, this goes through ConstellationControlMsg::TickAllAnimations, which we want to send less often. In turn this goes through LayoutControlMsg::TickAnimations, ConstellationControMsg::TickAnimations and to change_running_animations_state. Is this where we want to throttle the callback or should I climb the chain a little bit further?

@paulrouget
Copy link
Contributor Author

@paulrouget paulrouget commented Sep 29, 2015

The callback is triggered whenever the compositor runs, which is as fast as possible when animations are running (which is also wrong).

In my case, there was no animation.

Instead, it should only trigger the callback after an entire paint completes for the relevant pipeline.

What is wrong with keeping the same strategy (RFA when the compositor runs), but driving the compositor with vsync? Isn't that how it's supposed to work?

@glennw
Copy link
Member

@glennw glennw commented Sep 29, 2015

@paulrouget If we drive it with vsync we could get extra callbacks when the repainting is taking longer than a vsync period, and we should also support running in non-vsync mode correctly, I think.

@Yoric Great! I think what we want to do is throttle the callback in process_animations which is called each time the compositor draws a frame - in such a way that it only ticks animations if there isn't an outstanding paint being waited on for the relevant pipeline.

@pcwalton Does that sound correct to you?

@Yoric
Copy link
Contributor

@Yoric Yoric commented Sep 30, 2015

According to my trusty Gecko Compositor hacker @nical, we should really drive it with vsync. Preventing double-callbacks shouldn't be too hard, I guess.

@glennw Why do we want to support non-vsync mode, btw?

@nical
Copy link
Contributor

@nical nical commented Sep 30, 2015

Non-vsync mode is useful if you want to benchmark layout or rendering performance, but it's important for frame uniformity to drive RaF from vsyncs in the general case. Better yet, detecting that we are not keeping up with vsync and skipping every other vsyncs when that happens to keep frames uniforms (or when we want to save energy) is pretty useful.
It should not be hard to avoid the extra callback problem (you more or less just need to ignore incoming vsync notifications when you have a vsync callback that hasn't completed yet).

@glennw
Copy link
Member

@glennw glennw commented Sep 30, 2015

@Yoric Yep, exactly what nical said. I should have been clearer in saying that driving it from vsync is what we want, we just need to take account of those edge cases (vsync disabled, and painting not keeping up with vsync) and make sure they work too.

@Yoric
Copy link
Contributor

@Yoric Yoric commented Oct 1, 2015

@glennw Oh, so we have vsync support already?

@glennw
Copy link
Member

@glennw glennw commented Oct 1, 2015

@Yoric Only in so much as (I think) we set the default swap interval to vsync - it may even just be that it defaults to vsync on my linux machine.

@Yoric
Copy link
Contributor

@Yoric Yoric commented Oct 2, 2015

I'm a bit lost. If process_animations is called 1500 times per second, then so are process_pending_scroll_events and window.present() (which I understand is window flipping: documentation needed), so I guess we need to throttle all of these to vsync. Are you telling me that this is probably already the case at least on Linux?

If so, your earlier comment is a fallback for platforms that do not have vsync, right? I'm not sure I understand why finding out if the pipeline is waiting for a paint is related to the issue at hand (unless that's the vsync?) but I can certainly investigate this. Is this what does_layer_have_outstanding_paint_messages does or should I look on the other side of the pipeline?

@nical
Copy link
Contributor

@nical nical commented Oct 2, 2015

Yoric already knows about this document, but for the record, here is the design doc of the vsync stuff in gecko: https://dxr.mozilla.org/mozilla-central/source/gfx/doc/Silk.md

@pcwalton
Copy link
Contributor

@pcwalton pcwalton commented Oct 14, 2015

If window.present is being called over 60 FPS then we need to fix that problem at the windowing layer. That has to be fixed before anything else will work.

@paulrouget
Copy link
Contributor Author

@paulrouget paulrouget commented Jan 20, 2016

Now we are more advanced in browser.html support, this ends up being a problem.

Many animations in browser.html are RAF driven, and having ~700 calls per seconds is really impacting the performance.

@paulrouget
Copy link
Contributor Author

@paulrouget paulrouget commented Jan 21, 2016

If window.present is being called over 60 FPS then we need to fix that problem at the windowing layer. That has to be fixed before anything else will work.

It's called 60 FPS.

@glennw
Copy link
Member

@glennw glennw commented Jan 21, 2016

I think this will be a lot easier to solve with the WR design than the existing layers / painting design - I'll look into once I've cleared out my current bug list.

@jdm jdm removed the E-less easy label Jan 21, 2016
@glennw
Copy link
Member

@glennw glennw commented Jan 22, 2016

I pushed glennw@be3213e to the WR servo branch. In my test case, with vsync enabled (which is the default), I am getting rAF callbacks at exactly 60 fps, synced with the presentation interval.

I've also opened a PR to submit this to upstream servo here - #9401 - however even once this lands upstream there may be issues with non-WR painting backend in some cases.

@paulrouget
Copy link
Contributor Author

@paulrouget paulrouget commented Jan 22, 2016

@glennw on osx, I'm still getting ~500 calls.

@glennw
Copy link
Member

@glennw glennw commented Jan 22, 2016

It sounds like maybe vsync isn't working? Is there any way to verify if an application is running with vsync enabled?

@paulrouget
Copy link
Contributor Author

@paulrouget paulrouget commented Jan 22, 2016

I added to comment 0 the script I use to count the FPS.

@glennw
Copy link
Member

@glennw glennw commented Jan 22, 2016

I tried that test case on Linux and it's reporting 60 fps (well 61-62 but close enough for this test).

@paulrouget
Copy link
Contributor Author

@paulrouget paulrouget commented Jan 25, 2016

vsync is enabled on mac (at least, glutin's WindowBuilder::with_vsync is called).

@paulrouget
Copy link
Contributor Author

@paulrouget paulrouget commented Jan 26, 2016

Actually - I was wrong. It runs at 60 FPS.
Sorry sorry. I must have run a release build and compiled a debug build.

@paulrouget
Copy link
Contributor Author

@paulrouget paulrouget commented Jan 26, 2016

I figured it out. Using the -b option makes the FPS go crazy. Not using -b, it goes at 60 FPS.

@paulrouget
Copy link
Contributor Author

@paulrouget paulrouget commented Jan 26, 2016

@pcwalton
Copy link
Contributor

@pcwalton pcwalton commented Jan 27, 2016

@paulrouget Can we close this in favor of #9431?

@paulrouget
Copy link
Contributor Author

@paulrouget paulrouget commented Jan 27, 2016

@pcwalton This issue will get fixed once #9244 lands.

@paulrouget
Copy link
Contributor Author

@paulrouget paulrouget commented Jan 27, 2016

Sorry, I meant when #9401 lands.

@paulrouget
Copy link
Contributor Author

@paulrouget paulrouget commented Jan 28, 2016

(not a browserhtml-P1 anymore as it has been fixed in webrender)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
6 participants
You can’t perform that action at this time.