Closed Bug 1693176 Opened 3 years ago Closed 3 years ago

CSS animations in hidden panels cause the refresh driver to keep ticking

Categories

(Core :: DOM: Animation, defect)

defect

Tracking

()

RESOLVED FIXED
92 Branch
Performance Impact medium
Tracking Status
firefox92 --- fixed

People

(Reporter: mstange, Assigned: emilio)

References

(Blocks 2 open bugs)

Details

(Keywords: perf:resource-use, power)

Attachments

(3 files)

This was encountered by Henrik Skupin. Using the browser toolbox, he was able to find the permission-popup-permission-icon-in-use-blink animation.

Summary: We can get into a state where the parent process refresh driver keeps ticking even though nothing on the screen is changing (20% CPU) → CSS animations in hidden menupopups / panels cause the refresh driver to keep ticking

Here some steps:

  1. Use a Google Meet link and open the page
  2. Accept the permission for the microphone
  3. The animation of the camera icon in the url bar will start
  4. Click the permissions popup
  5. Close the page

Now the main process consumes quit a good amount of CPU until the permissions popup gets opened again.

The MBT showed me the animation for permission-popup-permission-icon-in-use-blink — CSS Animation. Clicking the icon to highlight it in the inspector the camera icon was selected: permission-popup-permission-icon camera-icon in-use.

Note that I closed the tab for Google Meet several hours ago.

Blocks: power-usage
Keywords: power
Whiteboard: [qf]

Looks like frames (nsIFrames) in the permission popup keep alive even if the popup window is closed. Is it intentional?

Wondering whether this is regressed by bug 1596897 or not.

CCing :pbz.

I don't see anything in the menu popup frame code that would destroy frames on hide. Probably so it can be shown again quickly?

(In reply to Hiroyuki Ikezoe (:hiro) from comment #3)

Looks like frames (nsIFrames) in the permission popup keep alive even if the popup window is closed. Is it intentional?

I think that's how popup windows are implemented, yes. When a popup is closed, its frames do not get destroyed. It's possible that we could change that, but it seems a bit risky.

And yes, while front-end can do various things to work around this, I think it would be preferable to have a general solution so that we don't tick animations which are in the frame subtree of an nsMenuPopupFrame which returns false from IsOpen().

(In reply to Markus Stange [:mstange] from comment #7)

(In reply to Hiroyuki Ikezoe (:hiro) from comment #3)

Looks like frames (nsIFrames) in the permission popup keep alive even if the popup window is closed. Is it intentional?

I think that's how popup windows are implemented, yes. When a popup is closed, its frames do not get destroyed. It's possible that we could change that, but it seems a bit risky.

Thanks for the quick reply.

And yes, while front-end can do various things to work around this, I think it would be preferable to have a general solution so that we don't tick animations which are in the frame subtree of an nsMenuPopupFrame which returns false from IsOpen().

D105377 should fix this issue (The change does check nsView::GetVisibility() state instead of the menu state though). That said, it just throttles animations in hidden popup window, so the refresh driver needs to keep ticking for the animations (for animation events, etc.). So eventually we should de-activate the presshell even if we keep frames in popup.

If the refresh driver keeps ticking, that won't help enough, I think. We want to stop waking up the CPU.

The popup's frame subtree is part of the same presshell as the main browser window, so we can't deactivate it.

Hmm, okay, then we should discard the frames in popup windows. (or front-end needs to stop animations when the popup is closed)

Okay, that does sound like the better solution. In the meantime, I've filed bug 1693201 for the front-end workaround.

Emilio, can you foresee any trouble from destroying frames in closed menupopups?

Flags: needinfo?(emilio)

I think it's worth a try. It was more risky when XBL was around (because frames also implied XBL bindings). But nowadays that shouldn't be a concern.

It'd be good if they used display: none... Should be easy-ish to prototype in menupopup.js by hiding the arrowscrollbox on popuphidden or such? Of course it'd be much better if it was done by Gecko but that requires more tweaking of the popup code.

Flags: needinfo?(emilio)

Ah, good idea.

Hmm, what about add-on popups which contain remote browsers? Do those handle display:none the way we want?

That is a good question. I think top level XUL <browser> elements don't care about whether they have frames much (in terms of throttling etc). I think we might start the load the first time they get frames, but otherwise is DOM connection what matters I believe.

This seems to work, though I've only done some light-weight testing.
Let's see what try says.

I did a quick test and extension browsers seem to behave nicely with this still.

Nice!

For historical context, this would also have helped with bug 1541314.

Furthermore, I just found bug 1413763 (which I'm not sure still reproduces), which has the fade-out opacity animation on the panel itself. The experimental patch does not destroy the panel's menupopup frame, so that case would not be fixed by it.

Emilio, can you foresee any trouble from destroying frames in closed menupopups?

This will destroy the native widget as well, no? That can have performance implications when quickly rolling over menus/submenus.

My patch only destroys the popup contents. Destroying the popup frame itself seems potentially trickier indeed, not only because of the widget thing, but also because all the state nsMenuPopupFrame stores.

Here's a try run for the patch above btw, let's see what breaks... https://treeherder.mozilla.org/jobs?repo=try&revision=fb0c5541e76222b22ff499052062278e98812453

There seem to be some failures with the <select> popup tests on windows and mac, but other than that it seems pretty workable... I can try to dig tomorrow.

Flags: needinfo?(emilio)

Current status is tests work, except some a11y focus mochitests which I'm pretty confused about.

Just a note: the STR in comment 2 will no longer reproduce this because this particular animation has been removed in bug 1687397.

Panels don't rely so much on the popup manager code to deal with
menuitems etc, so this is trivial and fixes the issue as reported.

I think it's pretty unlikely to have animated stuff in menulists /
menupopups, so this should get us most of the way.

Assignee: nobody → emilio
Status: NEW → ASSIGNED
Attachment #9203587 - Attachment description: Bug 1693176 - Destroy frames of contents inside menupopups. → Bug 1693176 - WIP - Destroy frames of contents inside menupopups.

So the a11y tests were a real bug about stuff we otherwise don't have a test for of course. I updated the commit message of my original phab revision, but basically doing this for menus/menulists is much harder because lots of the keyboard navigation code for them is implemented in terms of the frame tree.

However for the original case, which is a <panel>, this is trivial and works nicely. I think having animated stuff in a <menupopup> or <menulist> is not likely, so I think we should land the <panel> change without having to rewrite nsMenuPopupFrame / xul menus.

But let me know if that doesn't make sense for some reason :)

Flags: needinfo?(emilio)

That sounds reasonable! Removing "menupopups" from the bug title.

Summary: CSS animations in hidden menupopups / panels cause the refresh driver to keep ticking → CSS animations in hidden panels cause the refresh driver to keep ticking
Blocks: 1693446
Pushed by ealvarez@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/4a3f1073b7b5
Destroy frames of contents inside panels. r=Gijs

(In reply to Henrik Skupin (:whimboo) [⌚️UTC+1] from comment #2)

These steps to reproduce won't work anymore as bug 1687397 removed this specific animation.

Whiteboard: [qf] → [qf:p2:resource]
Attachment #9203848 - Attachment description: Bug 1693176 - Destroy frames of contents inside panels. r=Gijs,mconley → Bug 1693176 - Destroy frames of contents inside panels. r=Gijs
Flags: needinfo?(emilio)
Pushed by ealvarez@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/b3fab819b622
Destroy frames of contents inside panels. r=Gijs
Status: ASSIGNED → RESOLVED
Closed: 3 years ago
Resolution: --- → FIXED
Target Milestone: --- → 92 Branch
Blocks: 1746310
Blocks: 1714846
Performance Impact: --- → P2
Whiteboard: [qf:p2:resource]
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: