Clip raster tiles#9468
Conversation
b616b16 to
23cfe73
Compare
|
Is the actual raster clipping change here dependent on the IndexedPrimitive/Drawables/SegmentInfo changes or can those be an independent PR? |
|
It's not 100% dependent, but then we'd have to implement something that is essentially like that as well. We have the same code duplication for all of the buckets where we have complex code to make sure that all associated vertices for a number of primitives go into the same segment and. Are you saying we should merge |
|
|
||
| template <class Attributes> | ||
| class Segment { | ||
| class SegmentInfo { |
There was a problem hiding this comment.
Once you rebase on master to pick up #9433, I'd prefer to reverse the naming here: keep the Segment class as it is and move Segment::vertexArrays to a new class that composes it and Segment (name suggestion: DrawableSegment). Then give Drawable a DrawableSegmentVector rather than a SegmentVector. That will reduce the size of the diff here (no need to add .info. everywhere).
There was a problem hiding this comment.
That's what I attempted initially as well, but I opted to do it the other way around to keep the diff size small. However, I'm happy to rename Segment to DrawableSegment. Another candidate might be SegmentBuffers for naming alignment with VertexBuffer and IndexBuffer.
| offsetof(VertexType, a5) | ||
| }; | ||
|
|
||
| template <class A1> |
There was a problem hiding this comment.
Seems these are only needed for a test; can we move them there? Regular code shouldn't need to compare vertices. (Same with operator== for SegmentInfo.)
| template <class DrawMode, class LayoutVertex, class AttributeLayout> | ||
| class IndexedPrimitives { | ||
| public: | ||
| void add(std::initializer_list<LayoutVertex> v, |
There was a problem hiding this comment.
If we're to convert all the bucket types to IndexedPrimitives, this will be used in very hot code paths. How much overhead is there in creating initializer_lists, checking the segment capacity on every add, checking for valid indexes, etc.?
|
|
||
| private: | ||
| friend class Drawable<DrawMode, LayoutVertex, AttributeLayout>; | ||
| gl::VertexVector<LayoutVertex> vertices; |
There was a problem hiding this comment.
Note that the IndexedPrimitives abstraction won't work for the current implementation of FillBucket, which shares vertices between triangle and line primitives. It will work if we fix mapbox/mapbox-gl-js#2080 though. Are there any other scenarios where we would want to index the same set of vertices multiple ways? I can't think of any.
|
What is the advantage of this approach over using the depth buffer or stencil buffers (if we have any bits left there) to do clipping? |
I think we should either implement raster clipping without any major refactoring, or do the refactor to A partial refactor to |
| namespace mbgl { | ||
|
|
||
| // A TileMask is a set of TileIDs that describe what part of a tile should be rendered. I.e. it | ||
| // denotes the part of a tile that is covered by other/better tiles. If the entire tile should be |
There was a problem hiding this comment.
nit: these first two sentences seem to contradict each other — first that these parts of a tile "should be rendered" and then that this mask denotes parts that should be not be rendered
The advantage of this approach is that we're shading fewer pixels. Also, raster tiles aren't using stencil clipping since they typically load smaller tiles, which makes our stencil clipping mask overflow. It also allows us to draw the texture directly without first having to draw into the depth or stencil buffer. |
23cfe73 to
0ba701f
Compare
kkaefer
left a comment
There was a problem hiding this comment.
Removed the Drawables/Segment changes. Instead of having a TileMaskRepository, mask vertex buffers are now owned directly by the RasterBucket objects. When there is no masking happening (=default case when the entire tile is drawn), we're still sharing the global vertex buffer.
0ba701f to
4df6257
Compare
4df6257 to
1eff949
Compare
| // A TileMask is a set of TileIDs that describe what part of a tile should be rendered. It omits | ||
| // those parts of the tile that are covered by other/better tiles. If the entire tile should be | ||
| // rendered, it contains the { 0, 0, 0 } tile. If it's empty, no part of the tile will be rendered. | ||
| // TileMasks are typically generated with algorithm::updateTileMasks(). |
There was a problem hiding this comment.
The key to understanding how the TileMask is generated and used is to understand the relationship between:
- The tile ID of the tile being rendered
- The tile IDs of the renderable descendants of that tile
- The tile IDs of elements of the resulting TileMask
Can you spell out that relationship here or elsewhere, with either an algebraic definition or example?
There was a problem hiding this comment.
Added an example with a schematic drawing to the algorithm file.
| } | ||
| } | ||
|
|
||
| inline CanonicalTileID CanonicalTileID::operator-(const CanonicalTileID& rhs) const { |
There was a problem hiding this comment.
It seems like this definition of subtraction is specific to tile masks. Should it be a named function in tile_mask.hpp or update_tile_masks.hpp instead?
1eff949 to
244fa47
Compare
This changes our raster tile rendering to avoid rendering in the parts of a tile that have children for. It accomplishes this by generating vertex buffers that only have quads for the respective areas, rather than having one quad to fill the entire tile.
The first part of the PR refactors Vertex/Index/Segment vectors into their own
IndexedPrimitive/Drawableclasses. We can apply the same pattern for other buckets in a separate PR.The algorithm works by recursively descending from the tile in question and generating a list of tiles that would cover the tile, but not any of its children.
Finally, we're computing vertex buffers with our new
IndexedPrimitiveclass and store the vertex buffers in a repository object.Remaining tasks:
Fixes #9415, #7760, and #8678