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

Eliminate opaque pass rendering optimization #7063

Closed
mourner opened this issue Aug 1, 2018 · 7 comments
Closed

Eliminate opaque pass rendering optimization #7063

mourner opened this issue Aug 1, 2018 · 7 comments
Labels
needs discussion 💬 performance ⚡ Speed, stability, CPU usage, memory usage, or power usage refactoring 🏗️

Comments

@mourner
Copy link
Member

mourner commented Aug 1, 2018

@jfirebaugh on #2074 (comment):

I'm starting to think we should just not bother with a two-pass implementation. Currently, the only layers we draw in the opaque pass are opaque, non-patterned fills.

There are currently multiple serious issues the opaque pass causes that we can't easily solve without eliminating it:

Eliminating it will also reduce rendering code complexity overall. We may also need to do it anyway in future when implementing fill antialiasing, or a one-pass polygon type with fill + stroke.

We also don't really have a good idea of how much of an optimization this is. I suspect it might be insignificant given that most of the rendering time is spent on lines and symbols, not fills, and there aren't that many fragments under a solid fill on a typical map style.

Let's discuss what next steps we should take to make a decision whether to eliminate.

cc @jfirebaugh @ansis

@mourner mourner added performance ⚡ Speed, stability, CPU usage, memory usage, or power usage needs discussion 💬 refactoring 🏗️ labels Aug 1, 2018
@ansis
Copy link
Contributor

ansis commented Aug 1, 2018

@kkaefer do you remember the original motivation?

A side note: I think all those current issue could be solved without eliminating this (intended) optimization. Getting rid of it would be easier and better in a lot of ways, but I think it would be possible without.

@kkaefer
Copy link
Contributor

kkaefer commented Aug 1, 2018

The original motivation (ca. 5 years ago) was that I assumed it was faster since it had fewer pixels to shade. But we've never verified this hypothesis.

@mourner
Copy link
Member Author

mourner commented Aug 1, 2018

@kkaefer is there a way to reliably measure the difference? E.g. is there a way to track the total number of shaded pixels per draw?

@kkaefer
Copy link
Contributor

kkaefer commented Aug 1, 2018

We have a way to visualize the amount of shaded pixels in GL Native, but it's not necessarily a good measure of performance: shading a pixel takes up some bandwidth and GPU time, but trying to avoid to shade a pixel also takes time (we're currently using the depth buffer to mask out these areas).

@jfirebaugh
Copy link
Contributor

Patrick, the Pathfinder developer, is pretty insistent that minimizing overdraw is the best thing GPU-based vector renderers can do to increase performance.

https://twitter.com/pcwalton/status/978480183039557632
https://twitter.com/pcwalton/status/978493863064059905

Let's definitely benchmark this thoroughly.

@ansis
Copy link
Contributor

ansis commented Aug 14, 2018

I did some quick manual benchmarking. I loaded a close-up of the National Museum of Natural History which has two overlapping opaque fill layers (park, building) in this mapbox-streets style. I then set it to skip the rendering pass:

diff --git a/src/render/draw_fill.js b/src/render/draw_fill.js
index 3c853898f..b19801949 100644
--- a/src/render/draw_fill.js
+++ b/src/render/draw_fill.js
@@ -27,9 +27,7 @@ function drawFill(painter: Painter, sourceCache: SourceCache, layer: FillStyleLa
 
     const colorMode = painter.colorModeForRenderPass();
 
-    const pass = (!layer.paint.get('fill-pattern') &&
-        color.constantOr(Color.transparent).a === 1 &&
-        opacity.constantOr(0) === 1) ? 'opaque' : 'translucent';
+    const pass = 'translucent';
 
     // Draw fill
     if (painter.renderPass === pass) {

Both versions rendered at 60 fps so I set window.devicePixelRatio = 3 (instead of 2) to double the number of pixels being shaded and make the rendering fillrate-bound.

The version with the opaque pass rendered at ~45 fps while the translucent version rendered at ~35 fps.

screenshots of the overdraw screen shot 2018-08-14 at 2 31 34 pm screen shot 2018-08-14 at 2 06 17 pm screen shot 2018-08-14 at 2 07 04 pm

I did a second quick test with http://localhost:9966/debug/#6.88/38.825/-80.416 where we have a ton of overlapping translucent landuse polygons. If we force them to be opaque it goes from 40 fps to 60 fps. Opaqueness wouldn't work for landuse in this style, but the test does show how the opaque pass would make a huge difference in a style with plenty of overlapping opaque fill layers.


This isn't the most scientific benchmarking but I'm pretty sure the opaque pass would help us on less efficient styles (this test only had two overlapping layers), weaker hardware (not a macbook) or larger screens (a giant tv).

@jfirebaugh @mourner Is this thorough enough to settle this question? or do we want to be able to produce this difference on a real device with a real unmodified style (what counts as real?)?

@mourner
Copy link
Member Author

mourner commented Aug 14, 2018

@ansis that's a great way to benchmark! Thanks for doing this. It's definitely enough to convince me to leave the optimization in place for now. I'll close unless there are any objections.

@mourner mourner closed this as completed Aug 14, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs discussion 💬 performance ⚡ Speed, stability, CPU usage, memory usage, or power usage refactoring 🏗️
Projects
None yet
Development

No branches or pull requests

4 participants