Absolute- or fixed-position descendant of element with filter causes unnecessary recalculation
Reported by
tburn...@hubspot.com,
Jan 26 2017
|
||||||||
Issue descriptionChrome Version : 55.0.2883.95 OS Version: OS X 10.12.3 URLs (if applicable) : http://codepen.io/TrevorBurnham/pen/pRWOvL Other browsers tested: Add OK or FAIL after other browsers where you have tested this issue: Safari 10.0.3: OK Firefox 51.0.1: OK What steps will reproduce the problem? 1. Go to http://codepen.io/TrevorBurnham/pen/pRWOvL 2. Use the button to toggle `display: none` on the absolute-positioned element inside of the container with `filter: blur(3px)`. 3. Use Timeline tool to compare the page's performance performance between the two states. What is the expected result? Whether the absolute-positioned element in the blurred container has `display: none` or not should have no impact on page performance, since the element is not changing in any way, and furthermore has no content. What happens instead of that? In the state where the absolute-positioned element doesn't have `display: none`, the page heavily utilizes the GPU, apparently continuously repainting the blurred container. At a large enough window size, this causes the frame rate to drop. This is surprising because the page's sole animated element is fixed-positioned and not a descendant of the blurred container. The blurred container should only need to be painted once. Please provide any additional information below. Attach a screenshot if possible. UserAgentString: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36 I don't see any performance discrepancy between the two states of that page in Safari or Firefox. The `overflow: hidden` value in the wrapper around the blurred container is an important piece of the puzzle. Remove that rule and the discrepancy goes away. The Timeline indicates that the compositing heuristic that causes the absolute positioned ancestor to be promoted to its own layer (somehow causing its container to be repainted?) is "Has clipping ancestor." Side note: In the real application where I ran into this issue, the absolute-positioned elements in the blurred container were intended only for screen readers, using the common technique: .sr-only { position: absolute; clip: rect(0, 0, 0, 0); } So adding a special rule to treat elements with `clip: rect(0, 0, 0, 0)` the same as elements with `display: none` for compositing purposes would mitigate the issue.
,
Feb 3 2017
mac triage: Thank you for the detailed report! I lack the understanding of CSS to tell whether this behavior is right or not, so I'm routing this directly to the CSS team for triage.
,
Feb 6 2017
This sounds like it might be something for the paint team to look into - CSS doesn't directly control layerization.
,
Feb 7 2017
We should detect the empty clip rect and not draw the content. Totally ripe for optimization.
,
Feb 7 2017
,
Feb 12 2018
This issue has been Available for over a year. If it's no longer important or seems unlikely to be fixed, please consider closing it out. If it is important, please re-triage the issue. Sorry for the inconvenience if the bug really should have been left as Available. If you change it back, also remove the "Hotlist-Recharge-Cold" label. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
,
Feb 12 2018
Looking at repaint in Devtools, we are not repainting the background in the given test case, but it is also the case the removing the overflow-hidden on the background container doubles the frame rate. Over to cc for insight into what might be happening.
,
Feb 20 2018
Adding some folks, any thoughts as to whether we can optimize this?
,
Feb 21 2018
On my Linux machine with hardware compositing, the default has gpu main pegged at 30fps with NativeViewGLSurfaceGLX:RealSwapBuffers taking 30ms (unsurprisingly). Clicking the button results in a trace with 0.4ms swap buffers, and running at 60fps. So, it seems most likely that we're overloading the gpu. Looking at the render pass output, there's definitely a render pass with a filter that ends up being about half the page in size (the top half of the codepen ui is clipped). I looked at what the property tree builder was dealing with and there are no layers with empty size and masks to bounds, and so the property tree builder generates a number of clip nodes, none of which are empty. As far as I can tell through looking at the layer inputs and the property tree values, the compositor is doing what it has been told to do. I suspect this should be addressed at the paint layerization step in the pipeline. |
||||||||
►
Sign in to add a comment |
||||||||
Comment 1 by ranjitkan@chromium.org
, Jan 31 2017