| Summary: | Extremely low performance layer compositing with Google Maps API v3 | ||
|---|---|---|---|
| Product: | WebKit | Reporter: | Nick Dolezal <nick> |
| Component: | Layout and Rendering | Assignee: | Nobody <webkit-unassigned> |
| Status: | RESOLVED WORKSFORME | ||
| Severity: | Major | CC: | jond, simon.fraser, timothy, webkit-bug-importer |
| Priority: | P2 | Keywords: | InRadar |
| Version: | 528+ (Nightly build) | ||
| Hardware: | Mac (Intel) | ||
| OS: | OS X 10.10 | ||
| Attachments: | |||
|
Description
Nick Dolezal
2015-03-03 15:02:11 PST
Safari 8 and Chrome have different compositing layer configurations for the map tiles. Chrome tiles are: <div style="width: 256px; height: 256px; overflow: hidden; transform: translateZ(0px); position: absolute; left: 152px; top: 443px;"></div> but Safari 8 gets: <div style="width: 256px; height: 256px; position: absolute; left: 151px; top: 178px;"></div> Note the lack of transform property. (Another thing to note: Safari 8 still needs -webkit-transform). If you fix that does the story change? Hmmm, indeed. I made a methodological error in my testing. I confused the DOM styles from Safari's Develop -> User Agent -> Chrome with Chrome.app itself.
The useragent Safari reports for Develop -> User Agent -> Chrome is quite old, so I retested with a custom useragent string for Chrome 41. ("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36")
Plot twist: Under Chrome 41's user agent, Safari 8's performance was as expected. Moreover, -webkit-transform *is* getting set here as well, at least on some of the elements.
Further Tests: Firefox
Chrome 8 was set to the current stable Firefox UA ("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:36.0) Gecko/20100101 Firefox/36.0"), and retested.
Results: Chrome: Low FPS with recent Firefox UA set. Firefox: 30+ FPS.
The DOM in both Firefox.app and Safari with UA=FF, showed no zero-transforms getting set, nor any apparent analogs. I did not find a way to show compositing boundaries in Firefox, but the 3D view did show boundaries around the tiles. Unknown if compositing or just element.
Further Tests: Breaking Zero Transforms For Everyone
To better compare the underlying compositing behavior, it would be useful to disable the useragent-related zero transform hacks. I very crudely removed all the zero-transforms for both Chrome and Safari UA=Chrome 41. This was effective in causing both Chrome and Safari to revert to their instinctive layer-squashing behaviors.
Results:
Performance: Decreased performance for both; Chrome: 30-60 FPS, Safari: < 15 FPS and UI freezing. Difficult to separate out polling / DOM traversal overhead, but CPU use increased in Chrome to almost 100% across all cores, whereas Safari bottlenecked on a single core at 100%.
Squashing:
Chrome: Would not squash further than the cyan gridlines seen in "chrome40.png"; these appeared to be 128x128 point (256x256 px actual) tiles, and were unaligned on a block level with Web Mercator tiles.
Safari: Went all the way and squashed everything, looking identical to "safari8.png" -- no tile compositing boundaries.
The DOMs appeared similar, with Safari getting the vendor prefix (despite Chrome's UA...), and only transform-origin and transform-matrix were present on container divs I can see. Those are required for panning the map AFAIK, and I don't think can be reduced further.
Conclusions:
1. Google Maps API v3 is making the zero transform hacks for pretty much everyone who needs them... except Chrome 8 OS X.
2. The zero transform hack has a much more significant effect upon Safari than Chrome, though quantifying that for Chrome is difficult due to the testing performed.
3. Without the hack, both Safari and Chrome squash layers. Chrome will not squash as extensively as Safari. This may be related to the logic changes in the linked bugs.
4. A sparsity heuristic may potentially improve Safari's performance here, assuming it is doing so for Chrome. Unfortunately as long as Gmaps API v3 inserts stuff like this into the DOM for Chrome, the world will never know if the sparsity heuristic improved performance or not because it will never get used:
<img src="http://safecast.media.mit.edu/tilemap/TileGriddata512/9/452/197.png" draggable="false" style="width: 256px; height: 256px; -webkit-user-select: none; border: 0px; padding: 0px; margin: 0px; transform: translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px) translateZ(0px);">
Sidenote: Result of natural behavior in Chrome after panning a while. Zombies with a Z. pool.pop() and style += I'm guessing. That's 1KB as UTF-16. The map tile .png is 3KB. This is why hardcoded hacks are bad.
Will attach updated test case with the translateZ removal for Chrome.
Created attachment 247827 [details]
Test case .html only, v1.1. Button to remove zero transform hacks. Probes Chrome's squashing.
I think this discussion would be more productive if it included Google Maps engineers. Re #5: Made a request but you may need to follow-up. (I'm just some random person on the internets) Erratum to #3: All instances of "Chrome 8" should be "Safari 8". Two more things to add if I may; I tested other major web map APIs, and finally managed to test Chrome properly without translateZ(0). Scope: Other Map APIs I briefly tested every other major tiled web map API I could think of offhand. OpenLayers 1/2/3/Cs, Leaflet (MapBox), Bing Maps, and ArcGIS. Either these issues didn't apply (OL; giant canvas element) or more commonly, an analog of translateZ(0) was already getting set for both Chrome and Safari (Leaflet, Bing Maps). To be clear, the same core "layer smushing -> low tile FPS" issue is present. But because the workarounds normally prevent that, Safari 8 was merely the first to get a the-real-dark-souls-starts-here experience for any length of time. As the test below shows, Chrome also suffers when the useragent string stops matching. Potential risk exists for both browsers. Test: Chrome: No translateZ(0): Chrome's layering performance was isolated from the effects of translateZ(0) with a useragent override extension[1] which was set to Firefox's UA string. Results: Performance: Significant decrease in performance, though not as much as Safari under the same conditions. This was mostly a result of minimum framerate changes. Holding down left mouse and rapidly spinning the map in small-radius circles with Chrome's UA set to Firefox measured 30 FPS consistently. With Chrome's default UA it measured 55 FPS. Conclusion: This test provides further evidence both Chrome and Safari display suboptimal Gmaps API v3 tiled map performance without translateZ(0px), and that this has a more significant impact upon Safari than Chrome. Chromium issue 356734 [2] states "we don't create big squashing layers on maps". Unfortunately, internal layer squashing heuristics alone were unable to provide expected performance in this test. [1]: https://chrome.google.com/webstore/detail/user-agent-switcher/ffhkkpnppgnfaobgihpdblnhmmbodake [2]: https://code.google.com/p/chromium/issues/detail?id=356734 Google Maps bug 7756 created[1] per request. Likely nothing actionable for WebKit here? If so, this can be closed. [1] https://code.google.com/p/gmaps-api-issues/issues/detail?id=7756 Update: Reported as fixed by Google[1]. "This should now be fixed in the experimental (3.20) version and will be patched into release (3.19) tomorrow." [1] https://code.google.com/p/gmaps-api-issues/issues/detail?id=7756 Can confirm the fix, appears to be set as it was for the Safari 7 UA. Native Gmaps basemap: <div style="width: 256px; height: 256px; -webkit-transform: translateZ(0px); position: absolute; left: 1712px; top: -2389px; opacity: 1; transition: opacity 200ms ease-out; -webkit-transition: opacity 200ms ease-out;"> <img src="https://mts1.googleapis.com/vt?pb=!1m4!1m3!1i10!2i913!3i388!2m3!1e0!2sm!3i295000000!3m9!2sen-US!3sUS!5e18!12m1!1e47!12m3!1e37!2m1!1ssmartmaps!4e0!5m1!5f2" draggable="false" style="width: 256px; height: 256px; -webkit-user-select: none; border: 0px; padding: 0px; margin: 0px;"> </div> User raster layer: <div style="width: 256px; height: 256px; -webkit-transform: translateZ(0px); position: absolute; left: 944px; top: -2133px; opacity: 0.5;"> <img src="http://safecast.media.mit.edu/tilemap/TileGriddata/10/910/389.png" draggable="false" style="width: 256px; height: 256px; -webkit-user-select: none; border: 0px; padding: 0px; margin: 0px;"> </div> |