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
Do not use a fixed tile grid for vector rendering #799
Do not use a fixed tile grid for vector rendering #799
Conversation
This is ready for review now. |
@@ -305,15 +312,32 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame = | |||
layer = this.getVectorLayer(), | |||
tileGrid = this.tileGrid_; | |||
|
|||
// lazy tile grid creation | |||
if (!frameState.viewHints[ol.ViewHint.ANIMATING]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quick comment before actual review: should the above be if not animating and not interacting
? For example, I guess you don't want the cache to contain tiles at "while pinching" resolutions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I'll change that. Thanks!
All this in-place modification of the tile cache and messing about with the internals of a tilegrid is going to be slow and confusing. I'm strongly opposed to this approach. Surely there is a better way, |
The "messing about the internals of a tilegrid" is mine :) Andreas currently creates a new tile grid each time a new resolution should be inserted. I'm also not a big fan of the in-place modification of the tile cache, but I cannot see a better way. |
/** | ||
* @define {number} The lowest supported resolution value. | ||
*/ | ||
ol.renderer.canvas.MIN_RESOLUTION = 0.14929107086948487; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where does this magic number come from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Zoom level 21 in a default web mercator tiling scheme.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only other way I see (which I don't think would be faster or more elegant) is this:
|
if (!frameState.viewHints[ol.ViewHint.ANIMATING] && | ||
!frameState.viewHints[ol.ViewHint.INTERACTING]) { | ||
// avoid rendering issues for very high zoom levels | ||
var newResolution = Math.max(resolution, ol.renderer.canvas.MIN_RESOLUTION); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So does this mean that resolutions smaller than ol.renderer.canvas.MIN_RESOLUTION
(Google zoom level 21) are not supported by the canvas vector layer renderer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now, we run into coordinate range issues for very long line segments, which makes them disappear. This restriction will go away once we introduce clipping before rendering geometries. See #404.
When zooming in beyond level 21, vector rendering is still available, but will be scaled from this MIN_RESOLUTION.
I think that there are a number of other options, including:
The problem that this PR tries to address is just one aspect of a multitude of problems with the approach of rendering vector data into tiles and caching those tiles. Using tiles for vector layers means that vector layers aren't really vector layers. They're really tile layers where the rendering of the tiles happens to be done on the client instead of the server. This means that you get all the scaling artefacts associated with tile layers, and you don't get the nice sharp rendering that vector layers should provide at all resolutions. Using vector tiles has pathologically bad performance in several common circumstances:
In short, I think that this approach of rendering vector data into raster tiles is fundamentally flawed in terms of performance, image quality and scalability and it completely defeats the point of using vector data in the first place. I think we should find a better approach. |
@twpayne, despite your concerns, what would get worse if we merge this now? It is an improvement to what we have, it is self contained (i.e. does not touch other files), and can be revisited any time later. I could comment on all your points as well and find counter-arguments for most everything you say, but I'll rather enjoy the warm summer evening. |
I would be interested to hear the counter-arguments, but no rush. |
I would be interested in seeing your 'Please merge, but let's continue to discuss this'. No rush either, but I'd be more motivated to explain things like how I envision editing without redrawing tiles all the time and labeling when rotating after merging. And that discussion should rather go on the mailing list or a dedicated ticket. |
Let's continue to discuss this - either here or on the mailing list - but I don't think that this code should be merged. In my opinion, this is a very messy solution that does not correctly solve the issue. |
This blog post may be helpful: #764 is also relevant. |
@twpayne, this is getting ridiculous. From #764:
We're all psyched to see fully styled vector layers in WebGL, updated instantly with every frame, and with no images stored anywhere. But until we get there, we need a working alternative. The code to improve Canvas rendering is here, it's only waiting to be merged. |
It would be good for you to pick up this argument elsewhere @twpayne; it is counterproductive here. Rendering vector data to raster tiles is exactly the approach that has resulted in an explosion of popularity in slippy maps over the past ~10 years. I'm not saying you don't have valid points to make about alternatives in client side rendering (the approach has proven itself hugely successful on the server, but we're only starting to experiment with it here on the client). But I think injecting your arguments on this issue is only causing frustration. Let's try to work together on an alternative that can be compared for performance. Iterating through thousands of features with every mousemove has performance implications as well. |
@ahocevar one approach that I've been curious to try is to cache a single resolution only. This would support animated zooming (use previous resolution until animation ends) and minimizes redrawing on panning. I haven't fully reviewed your work here, but I'm curious what you think about the alternative. |
Sounds like a great approach @tschaub. We know now that the rendering itself is fast, we only don't want to do it during animations and interactions. So after your suggested change, whenever the view settles, we get a sharp rendered image at a native resolution, and don't need the overhead of a tile grid with multiple resolutions and a messy way to update the tile cache. Brilliant. Updating the pull request now. |
This makes more sense. Maybe vector layers should work more like single image layers than tile layers. It would be nice to be able to re-use the existing image layer renderers. Perhaps a vector layer could pretend to be a single image source? This can easily be hidden from the user (i.e. when a renderer needs to create a layer renderer for vector source, it internally creates a vector to single image layer bridge and passes this single image source to a single image layer renderer). |
Note that rendering vectors to a single image (or caching only a single resolution) will still suffer from the problems described in the aforementioned blog post:
Basically, we should avoid vector layer strategies that include caching pixels that are transparent. A good thought exercise is to consider the cost of rendering and compositing the vector layer if it only contains a few - or even no - features. |
It would be a straightforward enhancement to stop caching tiles that don't intersect any features. This should be handled in a separate issue (see #808). |
@@ -1,5 +1,6 @@ | |||
goog.provide('ol.renderer.canvas.VectorLayer'); | |||
|
|||
goog.require('goog.array'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused require.
This is awesome @ahocevar. Please address the minor comments above (about |
Instead, we create a new tile grid whenever renderFrame is called, no animation is active, and the resolution is not in the tile grid already. This gives better rendering results because we get vector tiles at native resolutions.
It seems that after this change the vector rending on mobile devices is broken. Test in Chrome Beta on Android. |
@mlegenhausen On my Android device, this change is not to blame. I do get points rendered, but no lines and polygons. And I went back through several revisons - all were the same. Unfortunately I cannot test on the native browser, because there are many more things broken. Repurposing today to mobile testing and fixing. |
@mlegenhausen What is the issue you are seeing? One that I am seeing is that when pinch-zooming, the vector layer does not get rendered at the new resolution, and is scaled instead. This is caused by #812. |
No blame at all. Great work! |
I'm having a few minor issues which I'm making tickets for, but this change has really improved usability for vectors. Great work! |
Instead, we create a new tile grid whenever renderFrame is
called, no animation is active, and the resolution is not in the
tile grid already. This gives better rendering results because
we get vector tiles at native resolutions.