From b616b16a8683c17bad1fc52e0110165ed703f4cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Mon, 10 Jul 2017 22:43:24 +0200 Subject: [PATCH] [core] generate masks for raster tiles to avoid painting over children --- cmake/core-files.cmake | 2 + cmake/test-files.cmake | 1 + src/mbgl/renderer/buckets/raster_bucket.cpp | 2 +- src/mbgl/renderer/painter.cpp | 17 -- src/mbgl/renderer/painter.hpp | 3 +- src/mbgl/renderer/render_tile.hpp | 2 + .../renderer/sources/render_raster_source.cpp | 2 + src/mbgl/renderer/tile_mask.hpp | 4 + src/mbgl/renderer/tile_mask_repository.cpp | 60 ++++++ src/mbgl/renderer/tile_mask_repository.hpp | 29 +++ test/renderer/tile_mask_repository.test.cpp | 194 ++++++++++++++++++ 11 files changed, 297 insertions(+), 19 deletions(-) create mode 100644 src/mbgl/renderer/tile_mask_repository.cpp create mode 100644 src/mbgl/renderer/tile_mask_repository.hpp create mode 100644 test/renderer/tile_mask_repository.test.cpp diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index 5564b10c736..f173ea3137c 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -199,6 +199,8 @@ set(MBGL_CORE_FILES src/mbgl/renderer/style_diff.cpp src/mbgl/renderer/style_diff.hpp src/mbgl/renderer/tile_mask.hpp + src/mbgl/renderer/tile_mask_repository.cpp + src/mbgl/renderer/tile_mask_repository.hpp src/mbgl/renderer/tile_parameters.hpp src/mbgl/renderer/tile_pyramid.cpp src/mbgl/renderer/tile_pyramid.hpp diff --git a/cmake/test-files.cmake b/cmake/test-files.cmake index 1c2cd76a388..ca8da7cb331 100644 --- a/cmake/test-files.cmake +++ b/cmake/test-files.cmake @@ -45,6 +45,7 @@ set(MBGL_TEST_FILES # renderer test/renderer/group_by_layout.test.cpp test/renderer/image_manager.test.cpp + test/renderer/tile_mask_repository.test.cpp # sprite test/sprite/sprite_loader.test.cpp diff --git a/src/mbgl/renderer/buckets/raster_bucket.cpp b/src/mbgl/renderer/buckets/raster_bucket.cpp index ea35582196b..526dac70522 100644 --- a/src/mbgl/renderer/buckets/raster_bucket.cpp +++ b/src/mbgl/renderer/buckets/raster_bucket.cpp @@ -33,7 +33,7 @@ void RasterBucket::render(Painter& painter, const RenderLayer& layer, const RenderTile& tile) { painter.renderRaster(parameters, *this, *layer.as(), tile.matrix, - painter.rasterDrawable); + painter.tileMaskRepository.getDrawable(painter.context, tile.mask)); } void RasterBucket::render(Painter& painter, diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index fa8756921c5..75dfceb4a6d 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -43,22 +43,6 @@ namespace mbgl { using namespace style; -static auto rasterPrimitives() { - IndexedPrimitives primitives; - primitives.add( - { - RasterProgram::layoutVertex({ 0, 0 }, { 0, 0 }), - RasterProgram::layoutVertex({ util::EXTENT, 0 }, { 32767, 0 }), - RasterProgram::layoutVertex({ 0, util::EXTENT }, { 0, 32767 }), - RasterProgram::layoutVertex({ util::EXTENT, util::EXTENT }, { 32767, 32767 }), - }, { - {{ 0, 1, 2 }}, - {{ 1, 2, 3 }}, - } - ); - return primitives; -} - static auto borderPrimitives() { IndexedPrimitives primitives; primitives.add( @@ -116,7 +100,6 @@ Painter::Painter(gl::Context& context_, const optional& programCacheDir) : context(context_), state(state_), - rasterDrawable(context, rasterPrimitives()), fillDrawable(context, fillPrimitives()), borderDrawable(context, borderPrimitives()), extrusionTextureDrawable(context, extrusionTexturePrimitives()) { diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp index 1aa3c78fce1..59af7e897da 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -168,7 +169,7 @@ class Painter : private util::noncopyable { std::unique_ptr overdrawPrograms; #endif - const Drawable rasterDrawable; + TileMaskRepository tileMaskRepository; const Drawable fillDrawable; const Drawable borderDrawable; const Drawable extrusionTextureDrawable; diff --git a/src/mbgl/renderer/render_tile.hpp b/src/mbgl/renderer/render_tile.hpp index 07e2d699f73..5f7ad91679c 100644 --- a/src/mbgl/renderer/render_tile.hpp +++ b/src/mbgl/renderer/render_tile.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -24,6 +25,7 @@ class RenderTile final { const UnwrappedTileID id; Tile& tile; ClipID clip; + TileMask mask; mat4 matrix; mat4 nearClippedMatrix; bool used = false; diff --git a/src/mbgl/renderer/sources/render_raster_source.cpp b/src/mbgl/renderer/sources/render_raster_source.cpp index 2006e31628d..e55950b809b 100644 --- a/src/mbgl/renderer/sources/render_raster_source.cpp +++ b/src/mbgl/renderer/sources/render_raster_source.cpp @@ -1,6 +1,7 @@ #include #include #include +#include namespace mbgl { @@ -57,6 +58,7 @@ void RenderRasterSource::update(Immutable baseImpl_, } void RenderRasterSource::startRender(Painter& painter) { + algorithm::updateTileMasks(tilePyramid.getRenderTiles()); tilePyramid.startRender(painter); } diff --git a/src/mbgl/renderer/tile_mask.hpp b/src/mbgl/renderer/tile_mask.hpp index a4cbff864fd..8859103ce8a 100644 --- a/src/mbgl/renderer/tile_mask.hpp +++ b/src/mbgl/renderer/tile_mask.hpp @@ -6,6 +6,10 @@ 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 +// 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(). using TileMask = std::set; } // namespace mbgl diff --git a/src/mbgl/renderer/tile_mask_repository.cpp b/src/mbgl/renderer/tile_mask_repository.cpp new file mode 100644 index 00000000000..5a0c8adaa43 --- /dev/null +++ b/src/mbgl/renderer/tile_mask_repository.cpp @@ -0,0 +1,60 @@ +#include +#include + +namespace mbgl { + +const Drawable& +TileMaskRepository::getDrawable(gl::Context& context, const TileMask& mask) { + auto it = drawables.find(mask); + if (it == drawables.end()) { + it = drawables + .emplace(std::piecewise_construct, std::forward_as_tuple(mask), + std::forward_as_tuple(context, getPrimitives(mask))) + .first; + } + return it->second; +} + +void TileMaskRepository::clear() { + drawables.clear(); +} + +IndexedPrimitives +TileMaskRepository::getPrimitives(const TileMask& mask) { + IndexedPrimitives primitives; + + 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 tlVertex = { static_cast(id.x * vertexExtent), + static_cast(id.y * vertexExtent) }; + const Point brVertex = { static_cast(tlVertex.x + vertexExtent), + static_cast(tlVertex.y + vertexExtent) }; + const Point tlTexture = { static_cast(id.x * textureExtent), + static_cast(id.y * textureExtent) }; + const Point brTexture = { static_cast(tlTexture.x + textureExtent), + static_cast(tlTexture.y + textureExtent) }; + + primitives.add( + { + RasterProgram::layoutVertex({ tlVertex.x, tlVertex.y }, + { tlTexture.x, tlTexture.y }), + RasterProgram::layoutVertex({ brVertex.x, tlVertex.y }, + { brTexture.x, tlTexture.y }), + RasterProgram::layoutVertex({ tlVertex.x, brVertex.y }, + { tlTexture.x, brTexture.y }), + RasterProgram::layoutVertex({ brVertex.x, brVertex.y }, + { brTexture.x, brTexture.y }), + }, + { + {{ 0, 1, 2 }}, + {{ 1, 2, 3 }}, + }); + } + + return primitives; +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/tile_mask_repository.hpp b/src/mbgl/renderer/tile_mask_repository.hpp new file mode 100644 index 00000000000..b8feb60145f --- /dev/null +++ b/src/mbgl/renderer/tile_mask_repository.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace mbgl { + +namespace gl { +class Context; +} // namespace gl + +class TileMaskRepository { +public: + const Drawable& + getDrawable(gl::Context&, const TileMask&); + + void clear(); + + static IndexedPrimitives + getPrimitives(const TileMask&); + +private: + std::map> drawables; +}; + +} // namespace mbgl diff --git a/test/renderer/tile_mask_repository.test.cpp b/test/renderer/tile_mask_repository.test.cpp new file mode 100644 index 00000000000..f1665f76810 --- /dev/null +++ b/test/renderer/tile_mask_repository.test.cpp @@ -0,0 +1,194 @@ +#include + +#include + +namespace std { + +template +std::ostream& operator<<(std::ostream& os, const std::array& array) { + os << "{{ "; + bool first = true; + for (const auto& t : array) { + if (!first) { + os << ", "; + } else { + first = false; + } + os << t; + } + return os << " }}"; +} + +} // namespace std + +namespace mbgl { +namespace gl { +namespace detail { + +template +std::ostream& operator<<(std::ostream& os, const Vertex& v) { + return os << "{ " << v.a1 << ", " << v.a2 << " }"; +} + +} // namespace detail +} // namespace gl +} // namespace mbgl + +using namespace mbgl; + +TEST(TileMaskRepository, Empty) { + auto primitives = TileMaskRepository::getPrimitives({}); + EXPECT_EQ((std::vector{}), primitives.getVertices().vector()); + EXPECT_EQ((std::vector{}), primitives.getIndices().vector()); + EXPECT_EQ((gl::SegmentInfoVector{}), primitives.getSegmentInfo()); +} + +TEST(TileMaskRepository, NoChildren) { + auto primitives = TileMaskRepository::getPrimitives({ CanonicalTileID{ 0, 0, 0 } }); + + EXPECT_EQ( + (std::vector{ + // 0/0/0 + RasterProgram::layoutVertex({ 0, 0 }, { 0, 0 }), + RasterProgram::layoutVertex({ 8192, 0 }, { 32768, 0 }), + RasterProgram::layoutVertex({ 0, 8192 }, { 0, 32768 }), + RasterProgram::layoutVertex({ 8192, 8192 }, { 32768, 32768 }), + }), + primitives.getVertices().vector()); + + EXPECT_EQ( + (std::vector{ + // 0/0/0 + 0, 1, 2, + 1, 2, 3, + }), + primitives.getIndices().vector()); + + + EXPECT_EQ( + (gl::SegmentInfoVector{ + { 0, 0, 4, 6 } + }), + primitives.getSegmentInfo()); +} + +TEST(TileMaskRepository, TwoChildren) { + auto primitives = TileMaskRepository::getPrimitives( + { CanonicalTileID{ 1, 0, 0 }, CanonicalTileID{ 1, 1, 1 } }); + + EXPECT_EQ( + (std::vector{ + // 1/0/1 + RasterProgram::layoutVertex({ 0, 0 }, { 0, 0 }), + RasterProgram::layoutVertex({ 4096, 0 }, { 16384, 0 }), + RasterProgram::layoutVertex({ 0, 4096 }, { 0, 16384 }), + RasterProgram::layoutVertex({ 4096, 4096 }, { 16384, 16384 }), + + // 1/1/1 + RasterProgram::layoutVertex({ 4096, 4096 }, { 16384, 16384 }), + RasterProgram::layoutVertex({ 8192, 4096 }, { 32768, 16384 }), + RasterProgram::layoutVertex({ 4096, 8192 }, { 16384, 32768 }), + RasterProgram::layoutVertex({ 8192, 8192 }, { 32768, 32768 }), + }), + primitives.getVertices().vector()); + + EXPECT_EQ( + (std::vector{ + // 1/0/1 + 0, 1, 2, + 1, 2, 3, + + // 1/1/1 + 4, 5, 6, + 5, 6, 7, + }), + primitives.getIndices().vector()); + + + EXPECT_EQ( + (gl::SegmentInfoVector{ + { 0, 0, 8, 12 } + }), + primitives.getSegmentInfo()); +} + +TEST(TileMaskRepository, Complex) { + auto primitives = TileMaskRepository::getPrimitives( + { CanonicalTileID{ 1, 0, 1 }, CanonicalTileID{ 1, 1, 0 }, CanonicalTileID{ 2, 2, 3 }, + CanonicalTileID{ 2, 3, 2 }, CanonicalTileID{ 3, 6, 7 }, CanonicalTileID{ 3, 7, 6 } }); + + EXPECT_EQ( + (std::vector{ + // 1/0/1 + RasterProgram::layoutVertex({ 0, 4096 }, { 0, 16384 }), + RasterProgram::layoutVertex({ 4096, 4096 }, { 16384, 16384 }), + RasterProgram::layoutVertex({ 0, 8192 }, { 0, 32768 }), + RasterProgram::layoutVertex({ 4096, 8192 }, { 16384, 32768 }), + + // 1/1/0 + RasterProgram::layoutVertex({ 4096, 0 }, { 16384, 0 }), + RasterProgram::layoutVertex({ 8192, 0 }, { 32768, 0 }), + RasterProgram::layoutVertex({ 4096, 4096 }, { 16384, 16384 }), + RasterProgram::layoutVertex({ 8192, 4096 }, { 32768, 16384 }), + + // 2/2/3 + RasterProgram::layoutVertex({ 4096, 6144 }, { 16384, 24576 }), + RasterProgram::layoutVertex({ 6144, 6144 }, { 24576, 24576 }), + RasterProgram::layoutVertex({ 4096, 8192 }, { 16384, 32768 }), + RasterProgram::layoutVertex({ 6144, 8192 }, { 24576, 32768 }), + + // 2/3/2 + RasterProgram::layoutVertex({ 6144, 4096 }, { 24576, 16384 }), + RasterProgram::layoutVertex({ 8192, 4096 }, { 32768, 16384 }), + RasterProgram::layoutVertex({ 6144, 6144 }, { 24576, 24576 }), + RasterProgram::layoutVertex({ 8192, 6144 }, { 32768, 24576 }), + + // 3/6/7 + RasterProgram::layoutVertex({ 6144, 7168 }, { 24576, 28672 }), + RasterProgram::layoutVertex({ 7168, 7168 }, { 28672, 28672 }), + RasterProgram::layoutVertex({ 6144, 8192 }, { 24576, 32768 }), + RasterProgram::layoutVertex({ 7168, 8192 }, { 28672, 32768 }), + + // 3/7/6 + RasterProgram::layoutVertex({ 7168, 6144 }, { 28672, 24576 }), + RasterProgram::layoutVertex({ 8192, 6144 }, { 32768, 24576 }), + RasterProgram::layoutVertex({ 7168, 7168 }, { 28672, 28672 }), + RasterProgram::layoutVertex({ 8192, 7168 }, { 32768, 28672 }), + }), + primitives.getVertices().vector()); + + EXPECT_EQ( + (std::vector{ + // 1/0/1 + 0, 1, 2, + 1, 2, 3, + + // 1/1/0 + 4, 5, 6, + 5, 6, 7, + + // 2/2/3 + 8, 9, 10, + 9, 10, 11, + + // 2/3/2 + 12, 13, 14, + 13, 14, 15, + + // 3/6/7 + 16, 17, 18, + 17, 18, 19, + + // 3/7/6 + 20, 21, 22, + 21, 22, 23, + }), + primitives.getIndices().vector()); + + + EXPECT_EQ( + (gl::SegmentInfoVector{ + { 0, 0, 24, 36 } + }), + primitives.getSegmentInfo()); +}