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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions benchmark/parse/tile_mask.benchmark.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include <benchmark/benchmark.h>

#include <mbgl/algorithm/update_tile_masks.hpp>

using namespace mbgl;

class MaskedRenderable {
public:
MaskedRenderable(const UnwrappedTileID& id_, TileMask&& mask_)
: id(id_), mask(std::move(mask_)) {
}

UnwrappedTileID id;
TileMask mask;
bool used = true;

void setMask(TileMask&& mask_) {
mask = std::move(mask_);
}
};

static void TileMaskGeneration(benchmark::State& state) {
std::vector<MaskedRenderable> renderables = {
MaskedRenderable{ UnwrappedTileID{ 12, 1028, 1456 }, {} },
MaskedRenderable{ UnwrappedTileID{ 13, 2056, 2912 }, {} },
MaskedRenderable{ UnwrappedTileID{ 13, 2056, 2913 }, {} },
MaskedRenderable{ UnwrappedTileID{ 14, 4112, 5824 }, {} },
MaskedRenderable{ UnwrappedTileID{ 14, 4112, 5827 }, {} },
MaskedRenderable{ UnwrappedTileID{ 14, 4114, 5824 }, {} },
MaskedRenderable{ UnwrappedTileID{ 14, 4114, 5825 }, {} },
};

while (state.KeepRunning()) {
algorithm::updateTileMasks<MaskedRenderable>({ renderables.begin(), renderables.end() });
}
}

BENCHMARK(TileMaskGeneration);
1 change: 1 addition & 0 deletions cmake/benchmark-files.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ set(MBGL_BENCHMARK_FILES

# parse
benchmark/parse/filter.benchmark.cpp
benchmark/parse/tile_mask.benchmark.cpp
benchmark/parse/vector_tile.benchmark.cpp

# src
Expand Down
1 change: 1 addition & 0 deletions cmake/benchmark.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ target_link_libraries(mbgl-benchmark
PRIVATE mbgl-core
)

target_add_mason_package(mbgl-benchmark PRIVATE boost)
target_add_mason_package(mbgl-benchmark PRIVATE benchmark)
target_add_mason_package(mbgl-benchmark PRIVATE rapidjson)
target_add_mason_package(mbgl-benchmark PRIVATE protozero)
Expand Down
2 changes: 2 additions & 0 deletions cmake/core-files.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ set(MBGL_CORE_FILES
src/mbgl/algorithm/generate_clip_ids.hpp
src/mbgl/algorithm/generate_clip_ids_impl.hpp
src/mbgl/algorithm/update_renderables.hpp
src/mbgl/algorithm/update_tile_masks.hpp

# annotation
include/mbgl/annotation/annotation.hpp
Expand Down Expand Up @@ -205,6 +206,7 @@ set(MBGL_CORE_FILES
src/mbgl/renderer/renderer_observer.hpp
src/mbgl/renderer/style_diff.cpp
src/mbgl/renderer/style_diff.hpp
src/mbgl/renderer/tile_mask.hpp
src/mbgl/renderer/tile_parameters.hpp
src/mbgl/renderer/tile_pyramid.cpp
src/mbgl/renderer/tile_pyramid.hpp
Expand Down
1 change: 1 addition & 0 deletions cmake/test-files.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ set(MBGL_TEST_FILES
test/algorithm/generate_clip_ids.test.cpp
test/algorithm/mock.hpp
test/algorithm/update_renderables.test.cpp
test/algorithm/update_tile_masks.test.cpp

# api
test/api/annotations.test.cpp
Expand Down
128 changes: 128 additions & 0 deletions src/mbgl/algorithm/update_tile_masks.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#pragma once

#include <mbgl/renderer/tile_mask.hpp>

#include <vector>
#include <functional>
#include <algorithm>

namespace mbgl {
namespace algorithm {

namespace {

template <typename Renderable>
void computeTileMasks(
const CanonicalTileID& root,
const UnwrappedTileID ref,
typename std::vector<std::reference_wrapper<Renderable>>::const_iterator it,
const typename std::vector<std::reference_wrapper<Renderable>>::const_iterator end,
TileMask& mask) {
// If the reference or any of its children is found in the list, we need to recurse.
for (; it != end; ++it) {
auto& renderable = it->get();
if (!renderable.used) {
continue;
}
if (ref == renderable.id) {
// The current tile is masked out, so we don't need to add them to the mask set.
return;
} else if (renderable.id.isChildOf(ref)) {
// There's at least one child tile that is masked out, so recursively descend.
for (const auto& child : ref.children()) {
computeTileMasks<Renderable>(root, child, it, end, mask);
}
return;
}
}

// We couldn't find a child, so it's definitely a masked part.
// Compute the difference between the root tile ID and the reference tile ID, since TileMask
// elements are always relative (see below for explanation).
const uint8_t diffZ = ref.canonical.z - root.z;
mask.emplace(diffZ, ref.canonical.x - (root.x << diffZ), ref.canonical.y - (root.y << diffZ));
}

} // namespace

// Updates the TileMasks for all renderables. Renderables are objects that have an UnwrappedTileID
// property indicating where they should be rendered on the screen. A TileMask describes all regions
// within that tile that are *not* covered by other Renderables.
// Example: Renderables in our list are 2/1/3, 3/3/6, and 4/5/13. The schematic for creating the
// TileMask for 2/1/3 looks like this:
//
// ┌────────┬────────┬─────────────────┐
// │ │ │#################│
// │ 4/4/12 │ 4/5/12 │#################│
// │ │ │#################│
// ├──────3/2/6──────┤#####3/3/6#######│
// │ │########│#################│
// │ 4/4/13 │#4/5/13#│#################│
// │ │########│#################│
// ├────────┴──────2/1/3───────────────┤
// │ │ │
// │ │ │
// │ │ │
// │ 3/2/7 │ 3/3/7 │
// │ │ │
// │ │ │
// │ │ │
// └─────────────────┴─────────────────┘
//
// The TileMask for 2/1/3 thus consists of the tiles 4/4/12, 4/5/12, 4/4/13, 3/2/7, and 3/3/7,
// but it does *not* include 4/5/13, and 3/3/6, since these are other Renderables.
// A TileMask always contains TileIDs *relative* to the tile it is generated for, so 2/1/3 is
// "subtracted" from these TileIDs. The final TileMask for 2/1/3 will thus be:
//
// ┌────────┬────────┬─────────────────┐
// │ │ │#################│
// │ 2/0/0 │ 2/1/0 │#################│
// │ │ │#################│
// ├────────┼────────┤#################│
// │ │########│#################│
// │ 2/0/1 │########│#################│
// │ │########│#################│
// ├────────┴────────┼─────────────────┤
// │ │ │
// │ │ │
// │ │ │
// │ 1/0/1 │ 1/1/1 │
// │ │ │
// │ │ │
// │ │ │
// └─────────────────┴─────────────────┘
//
// Only other Renderables that are *children* of the Renderable we are generating the mask for will
// be considered. For example, adding a Renderable with TileID 4/8/13 won't affect the TileMask for
// 2/1/3, since it is not a descendant of it.
template <typename Renderable>
void updateTileMasks(std::vector<std::reference_wrapper<Renderable>> renderables) {
std::sort(renderables.begin(), renderables.end(),
[](const Renderable& a, const Renderable& b) { return a.id < b.id; });

TileMask mask;
const auto end = renderables.end();
for (auto it = renderables.begin(); it != end; it++) {
auto& renderable = it->get();
if (!renderable.used) {
continue;
}
// Try to add all remaining ids as children. We sorted the tile list
// by z earlier, so all preceding items cannot be children of the current
// tile. We also compute the lower bound of the next wrap, because items of the next wrap
// can never be children of the current wrap.
auto child_it = std::next(it);
const auto children_end = std::lower_bound(
child_it, end,
UnwrappedTileID{ static_cast<int16_t>(renderable.id.wrap + 1), { 0, 0, 0 } },
[](auto& a, auto& b) { return a.get().id < b; });

mask.clear();
computeTileMasks<Renderable>(renderable.id.canonical, renderable.id, child_it, children_end,
mask);
renderable.setMask(std::move(mask));
}
}

} // namespace algorithm
} // namespace mbgl
1 change: 1 addition & 0 deletions src/mbgl/gl/index_buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class IndexVector {
bool empty() const { return v.empty(); }
void clear() { v.clear(); }
const uint16_t* data() const { return v.data(); }
const std::vector<uint16_t>& vector() const { return v; }

private:
std::vector<uint16_t> v;
Expand Down
1 change: 1 addition & 0 deletions src/mbgl/gl/vertex_buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class VertexVector {
bool empty() const { return v.empty(); }
void clear() { v.clear(); }
const Vertex* data() const { return v.data(); }
const std::vector<Vertex>& vector() const { return v; }

private:
std::vector<Vertex> v;
Expand Down
65 changes: 64 additions & 1 deletion src/mbgl/renderer/buckets/raster_bucket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ void RasterBucket::upload(gl::Context& context) {
if (!texture) {
texture = context.createTexture(*image);
}
if (!vertices.empty()) {
if (!segments.empty()) {
vertexBuffer = context.createVertexBuffer(std::move(vertices));
indexBuffer = context.createIndexBuffer(std::move(indices));
}
Expand All @@ -45,6 +45,69 @@ void RasterBucket::setImage(std::shared_ptr<PremultipliedImage> image_) {
uploaded = false;
}

void RasterBucket::setMask(TileMask&& mask_) {
if (mask == mask_) {
return;
}

mask = std::move(mask_);
clear();

if (mask == TileMask{ { 0, 0, 0 } }) {
// We want to render the full tile, and keeping the segments/vertices/indices empty means
// using the global shared buffers for covering the entire tile.
return;
}

// Create a new segment so that we will upload (empty) buffers even when there is nothing to
// draw for this tile.
segments.emplace_back(0, 0);

constexpr const uint16_t vertexLength = 4;

// Create the vertex buffer for the specified tile mask.
for (const auto& id : mask) {
// Create a quad for every masked tile.
const int32_t vertexExtent = util::EXTENT >> id.z;
const int32_t textureExtent = 32768 >> id.z;

const Point<int16_t> tlVertex = { static_cast<int16_t>(id.x * vertexExtent),
static_cast<int16_t>(id.y * vertexExtent) };
const Point<int16_t> brVertex = { static_cast<int16_t>(tlVertex.x + vertexExtent),
static_cast<int16_t>(tlVertex.y + vertexExtent) };
const Point<uint16_t> tlTexture = { static_cast<uint16_t>(id.x * textureExtent),
static_cast<uint16_t>(id.y * textureExtent) };
const Point<uint16_t> brTexture = { static_cast<uint16_t>(tlTexture.x + textureExtent),
static_cast<uint16_t>(tlTexture.y + textureExtent) };

if (segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) {
// Move to a new segments because the old one can't hold the geometry.
segments.emplace_back(vertices.vertexSize(), indices.indexSize());
}

vertices.emplace_back(
RasterProgram::layoutVertex({ tlVertex.x, tlVertex.y }, { tlTexture.x, tlTexture.y }));
vertices.emplace_back(
RasterProgram::layoutVertex({ brVertex.x, tlVertex.y }, { brTexture.x, tlTexture.y }));
vertices.emplace_back(
RasterProgram::layoutVertex({ tlVertex.x, brVertex.y }, { tlTexture.x, brTexture.y }));
vertices.emplace_back(
RasterProgram::layoutVertex({ brVertex.x, brVertex.y }, { brTexture.x, brTexture.y }));

auto& segment = segments.back();
assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max());
const uint16_t offset = segment.vertexLength;

// 0, 1, 2
// 1, 2, 3
indices.emplace_back(offset, offset + 1, offset + 2);
indices.emplace_back(offset + 1, offset + 2, offset + 3);

segment.vertexLength += vertexLength;
segment.indexLength += 6;
}
}

bool RasterBucket::hasData() const {
return !!image;
}
Expand Down
4 changes: 4 additions & 0 deletions src/mbgl/renderer/buckets/raster_bucket.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <mbgl/gl/vertex_buffer.hpp>
#include <mbgl/programs/raster_program.hpp>
#include <mbgl/renderer/bucket.hpp>
#include <mbgl/renderer/tile_mask.hpp>
#include <mbgl/util/image.hpp>
#include <mbgl/util/mat4.hpp>
#include <mbgl/util/optional.hpp>
Expand All @@ -21,8 +22,11 @@ class RasterBucket : public Bucket {

void clear();
void setImage(std::shared_ptr<PremultipliedImage>);
void setMask(TileMask&&);

std::shared_ptr<PremultipliedImage> image;
optional<gl::Texture> texture;
TileMask mask{ { 0, 0, 0 } };

// Bucket specific vertices are used for Image Sources only
// Raster Tile Sources use the default buffers from Painter
Expand Down
17 changes: 13 additions & 4 deletions src/mbgl/renderer/layers/render_raster_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,19 @@ void RenderRasterLayer::render(PaintParameters& parameters, RenderSource* source
parameters.context.bindTexture(*bucket.texture, 0, gl::TextureFilter::Linear);
parameters.context.bindTexture(*bucket.texture, 1, gl::TextureFilter::Linear);

draw(tile.matrix,
parameters.staticData.rasterVertexBuffer,
parameters.staticData.quadTriangleIndexBuffer,
parameters.staticData.rasterSegments);
if (bucket.vertexBuffer && bucket.indexBuffer && !bucket.segments.empty()) {
// Draw only the parts of the tile that aren't drawn by another tile in the layer.
draw(tile.matrix,
*bucket.vertexBuffer,
*bucket.indexBuffer,
bucket.segments);
} else {
// Draw the full tile.
draw(tile.matrix,
parameters.staticData.rasterVertexBuffer,
parameters.staticData.quadTriangleIndexBuffer,
parameters.staticData.rasterSegments);
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/mbgl/renderer/render_tile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ mat4 RenderTile::translatedClipMatrix(const std::array<float, 2>& translation,
return translateVtxMatrix(nearClippedMatrix, translation, anchor, state, false);
}

void RenderTile::setMask(TileMask&& mask) {
tile.setMask(std::move(mask));
}

void RenderTile::startRender(PaintParameters& parameters) {
tile.upload(parameters.context);

Expand Down
2 changes: 2 additions & 0 deletions src/mbgl/renderer/render_tile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <mbgl/util/mat4.hpp>
#include <mbgl/util/clip_id.hpp>
#include <mbgl/style/types.hpp>
#include <mbgl/renderer/tile_mask.hpp>

#include <array>

Expand Down Expand Up @@ -36,6 +37,7 @@ class RenderTile final {
style::TranslateAnchorType anchor,
const TransformState&) const;

void setMask(TileMask&&);
void startRender(PaintParameters&);
void finishRender(PaintParameters&);

Expand Down
2 changes: 2 additions & 0 deletions src/mbgl/renderer/sources/render_raster_source.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <mbgl/renderer/sources/render_raster_source.hpp>
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/tile/raster_tile.hpp>
#include <mbgl/algorithm/update_tile_masks.hpp>

namespace mbgl {

Expand Down Expand Up @@ -57,6 +58,7 @@ void RenderRasterSource::update(Immutable<style::Source::Impl> baseImpl_,
}

void RenderRasterSource::startRender(PaintParameters& parameters) {
algorithm::updateTileMasks(tilePyramid.getRenderTiles());
tilePyramid.startRender(parameters);
}

Expand Down
Loading