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

Batch polygon and circle fills and strokes #5196

Merged
merged 3 commits into from
Aug 24, 2016

Conversation

ahocevar
Copy link
Member

@ahocevar ahocevar commented Apr 7, 2016

Fixes #4232.

Better solution than the reverted one from #5149.

@ahocevar ahocevar force-pushed the batch-fill-stroke branch 2 times, most recently from e33d467 to a6fd547 Compare April 7, 2016 16:35
@ahocevar
Copy link
Member Author

ahocevar commented Apr 7, 2016

Opened for discussion:

The problem with batching fills and strokes is that overlapping polygons and circles with transparency won't have increased opacity. See #5179 (comment). Maybe there is a way to achieve fill overlap when applying a fill to a path that has overlaps, but I haven't found one.

One way to deal with this would be to make rendering behaviour configurable, so users can decide whether they want increased performance and no increased opacity on overlapping features with transparency, or features with true visual overlap at the cost of poorer performance.

Ideas?

@ahocevar
Copy link
Member Author

ahocevar commented Apr 7, 2016

How about this: when creating the replay, we check if there is any opacity. If so, we do not batch. Otherwise we do. I can update the pull request easily for a proof of concept.

@ahocevar ahocevar force-pushed the batch-fill-stroke branch 2 times, most recently from 5391a0d to 81498bf Compare April 7, 2016 21:11
@ahocevar ahocevar changed the title [WIP] Batch polygon and circle fills and strokes Batch polygon and circle fills and strokes Apr 7, 2016
@ahocevar
Copy link
Member Author

ahocevar commented Apr 7, 2016

I think this is a nice approach. Ready for review.

@ahocevar ahocevar force-pushed the batch-fill-stroke branch 5 times, most recently from 3407ceb to 59d6066 Compare April 8, 2016 10:18
@bjornharrtell
Copy link
Contributor

While I agree this approach is a nice default that works, I would find an option to force the batching always on useful in cases where I don't care about the opacity-correctness.

@@ -1440,13 +1484,20 @@ ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyle = function(fillStyle
var fillStyleColor = fillStyle.getColor();
state.fillStyle = ol.colorlike.asColorLike(fillStyleColor ?
fillStyleColor : ol.render.canvas.defaultFillStyle);
if (!this.transparency && ol.color.isRgba(state.fillStyle)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since ol.color.isRgba() is only used to test if alpha is not 1, it would be simpler just to have ol.color.isOpaque() or something (rather than first testing if it is RGBA and then creating an array and then testing the alpha value).

@tschaub
Copy link
Member

tschaub commented Apr 14, 2016

I don't want to rain on the parade, but I'm dubious about the effort to batch fills and strokes in this way. Here is a picture with batched fills and strokes:

image

I don't think this is what people want.

I'm also curious about how this affects what is reported in #4232, since I think that with the changes here, things are not being batched (because this.transparency is true whenever the red value is not 1, see #5196 (comment)).

@tschaub
Copy link
Member

tschaub commented Apr 14, 2016

I can imagine we could gain performance when there is no fill or no stroke. In those cases, we could defer stroking or filling (respectively) until the end. We could also delay stroking or filling until a fill or stroke is encountered (no need to stroke until you are going to fill and no need to fill until you are going to stroke). But these performance gains would be limited to pretty narrow cases.

@ahocevar
Copy link
Member Author

ahocevar commented Apr 18, 2016

Thanks @tschaub and @bjornharrtell for the valuable feedback. Based on that, I got rid of the opacity guessing game and introduced a new overlaps option for ol.source.Vector and ol.source.VectorTile, which allows users to decide whether the fill and stroke optimisations should be applied. Does this look better to you now?

@ahocevar ahocevar force-pushed the batch-fill-stroke branch 2 times, most recently from 695484d to 259b601 Compare April 18, 2016 09:01
@bjornharrtell
Copy link
Contributor

Looks good to me. I like the note on which kind of data this works on, another argument for my mission to convince people to work with non-overlapping topological data.

var pendingFill = 0;
var pendingStroke = 0;
var batchSize =
this.instructions != instructions || this.overlaps ? 0 : 200;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious about the 200 here. Did you find that performance is degraded if the batch size gets too big? It might be nice to document the justification for this default on its own line.

@tschaub
Copy link
Member

tschaub commented Apr 19, 2016

This sounds like a nice solution @ahocevar. It looks like your tests may cover it, but it would be even clearer to see rendering tests for overlaps: false with and without changing stroke and fill styles (to make sure we always properly stroke/fill when the styles change).

@ahocevar
Copy link
Member Author

Thanks for the review @tschaub. I have addressed your comments. Can you take another look please?

@ahocevar
Copy link
Member Author

Is this good to merge now @tschaub?

@ahocevar ahocevar force-pushed the batch-fill-stroke branch 2 times, most recently from 0b56136 to b521675 Compare April 28, 2016 14:02
Instead of deciding whether to batch fills and strokes by looking at the
opacity of the style, we now rely on user input.
@ahocevar
Copy link
Member Author

Rebased one more time.

@@ -4416,6 +4417,17 @@ olx.source.VectorTileOptions.prototype.logo;


/**
* This source may have overlapping geometries. Default is `true`. Setting this
* to `false` (e.g. for sources with polygons that represent adminstrative
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

administrative

@bartvde
Copy link
Member

bartvde commented Aug 23, 2016

LGTM @ahocevar

@ahocevar
Copy link
Member Author

Thanks for the reviews @tschaub and @bartvde.

@ahocevar ahocevar merged commit b7c84b2 into openlayers:master Aug 24, 2016
@ahocevar ahocevar deleted the batch-fill-stroke branch August 24, 2016 10:02
@probins
Copy link
Contributor

probins commented Aug 24, 2016

sorry for being late, but shouldn't this addition to the API be documented in the release notes?

@ahocevar
Copy link
Member Author

sorry for being late, but shouldn't this addition to the API be documented in the release notes?

Changes like this can be added to the release notes by the release manager when the release is created.

@jeroenvheel
Copy link

the performance boost with this change is amazing !!

@mstrop
Copy link

mstrop commented Nov 28, 2016

This says the issue #4232 is closed by this issue, I but still have terrible performance issue using IE (11 or Edge) - FF is a bit better, but not much. I use OL 3.19 version. Is there any progress on this?

@ahocevar
Copy link
Member Author

@mstrop Have you configured your source with overlaps: false?

@mstrop
Copy link

mstrop commented Nov 28, 2016

Yep, both - with and without. The difference is minimal. In addition to this, having the source defined as overlaps: false is causing display bugs for certain zooms.

image

@ahocevar
Copy link
Member Author

@mstrop Looks like your source does not have topological data, so you cannot use the overlaps: false option anyway. I think you'll have to apply different optimisations here, because your use case is not one that this fix was made for.

@mstrop
Copy link

mstrop commented Nov 28, 2016

@ahocevar ups, it's not a good message. Is there a chance this issue will be solved in future?

@ahocevar
Copy link
Member Author

@mstrop The only two places where I see additional potential for library side performance optimization is text and regular shape (including circle) rendering.

In your case, however, I suspect that you could optimize the style functions for your vector layers on the application level.

@mstrop
Copy link

mstrop commented Nov 28, 2016

@ahocevar thanks a lot.

@mstrop
Copy link

mstrop commented Dec 13, 2016

@ahocevar sry, one more question - I was thinking about your comment "I suspect that you could optimize the style functions for your vector layers on the application level". What is relation between a styling function and forEachFeatureAtPixel method? I use forEachFeatureAtPixel inside pointer move event as I need to change cursor in case it hovers above a feature. So the styling function is not called as the map is not being redrawn. Or am I missing anything?

@ahocevar
Copy link
Member Author

Even if you are only using forEachFeatureAtPixel for changing the cursor, without highlighting any features on the map, the style function will be called. Because for hit detection, features near the cursor will be rendered to a hidden small canvas to detect which features are rendered at the cursor location.

@mstrop
Copy link

mstrop commented Dec 13, 2016

@ahocevar thanks a lot for your very prompt response. I am really sorry, but I don't agree with you - I just made a quick test - I placed console.log(new Date().getTime()); as the first row of my styling function - sure, it overloads my console when I move the map, but there is no single record when the map is static and I just move the cursor above it.

@ahocevar
Copy link
Member Author

ahocevar commented Dec 13, 2016

My mistake @mstrop. The style function is called when creating the replay, not when replaying. And during mousemoves, it is only replayed.

However, without seeing your code, it is hard to guess what could be the culprit. Does your vector source use a spatial index? Have you tried with a smaller renderBuffer configured on your vector layer? For polygons, you can set it to half of the stroke width instead of the default of 100, and that will give you a massive performance gain, especially when your polygons are small at the viewed resolution.

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

Successfully merging this pull request may close these issues.

None yet

8 participants