Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Clip raster tiles #9468

Merged
merged 2 commits into from
Jul 24, 2017
Merged

Clip raster tiles #9468

merged 2 commits into from
Jul 24, 2017

Conversation

kkaefer
Copy link
Member

@kkaefer kkaefer commented Jul 10, 2017

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/Drawable classes. 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 IndexedPrimitive class and store the vertex buffers in a repository object.

Remaining tasks:

  • Render test
  • Delete unused mask buffers

Fixes #9415, #7760, and #8678

@kkaefer kkaefer added Core The cross-platform C++ core, aka mbgl rendering labels Jul 10, 2017
@kkaefer kkaefer requested review from jfirebaugh, tmpsantos and lbud July 10, 2017 20:49
@kkaefer kkaefer force-pushed the clip-raster-tiles branch from b616b16 to 23cfe73 Compare July 11, 2017 12:59
@jfirebaugh
Copy link
Contributor

Is the actual raster clipping change here dependent on the IndexedPrimitive/Drawables/SegmentInfo changes or can those be an independent PR?

@kkaefer
Copy link
Member Author

kkaefer commented Jul 13, 2017

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 IndexedPrimitive/Drawables/SegmentInfo before or after raster clipping?

@@ -11,23 +11,39 @@
namespace mbgl {
namespace gl {

template <class Attributes>
class Segment {
class SegmentInfo {
Copy link
Contributor

Choose a reason for hiding this comment

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

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).

Copy link
Member Author

Choose a reason for hiding this comment

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

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.

@@ -221,6 +221,32 @@ const std::size_t Vertex<A1, A2, A3, A4, A5>::attributeOffsets[5] = {
offsetof(VertexType, a5)
};

template <class A1>
Copy link
Contributor

Choose a reason for hiding this comment

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

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,
Copy link
Contributor

Choose a reason for hiding this comment

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

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;
Copy link
Contributor

Choose a reason for hiding this comment

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

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.

@ansis
Copy link
Contributor

ansis commented Jul 14, 2017

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?

@jfirebaugh
Copy link
Contributor

Are you saying we should merge IndexedPrimitive/Drawables/SegmentInfo before or after raster clipping?

I think we should either implement raster clipping without any major refactoring, or do the refactor to IndexedPrimitive/Drawable first, in a separate PR, and do it fully, and then implement raster clipping on top of that.

A partial refactor to IndexedPrimitive/Drawable combined with implementing raster clipping leaves the codebase in an inconsistent state, and makes reviewing the changes more difficult.

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
Copy link
Contributor

Choose a reason for hiding this comment

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

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

@kkaefer
Copy link
Member Author

kkaefer commented Jul 20, 2017

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?

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.

Copy link
Member Author

@kkaefer kkaefer left a comment

Choose a reason for hiding this comment

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

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.

// 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().
Copy link
Contributor

Choose a reason for hiding this comment

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

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?

Copy link
Member Author

Choose a reason for hiding this comment

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

Added an example with a schematic drawing to the algorithm file.

@@ -126,6 +127,15 @@ inline CanonicalTileID CanonicalTileID::scaledTo(uint8_t targetZ) const {
}
}

inline CanonicalTileID CanonicalTileID::operator-(const CanonicalTileID& rhs) const {
Copy link
Contributor

Choose a reason for hiding this comment

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

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?

Copy link
Member Author

Choose a reason for hiding this comment

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

Inlined this function

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Core The cross-platform C++ core, aka mbgl rendering
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants