[core] generate masks for raster tiles to avoid painting over children
This commit is contained in:
Submodule mapbox-gl-js updated: 31444a72c2...0c225291ab
@@ -26,6 +26,7 @@ public:
|
||||
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;
|
||||
|
||||
@@ -28,6 +28,7 @@ public:
|
||||
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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -21,8 +22,11 @@ public:
|
||||
|
||||
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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -36,6 +37,7 @@ public:
|
||||
style::TranslateAnchorType anchor,
|
||||
const TransformState&) const;
|
||||
|
||||
void setMask(TileMask&&);
|
||||
void startRender(PaintParameters&);
|
||||
void finishRender(PaintParameters&);
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -57,6 +58,7 @@ void RenderRasterSource::update(Immutable<style::Source::Impl> baseImpl_,
|
||||
}
|
||||
|
||||
void RenderRasterSource::startRender(PaintParameters& parameters) {
|
||||
algorithm::updateTileMasks(tilePyramid.getRenderTiles());
|
||||
tilePyramid.startRender(parameters);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ void RasterTile::setData(std::shared_ptr<const std::string> data,
|
||||
worker.invoke(&RasterTileWorker::parse, data);
|
||||
}
|
||||
|
||||
void RasterTile::onParsed(std::unique_ptr<Bucket> result) {
|
||||
void RasterTile::onParsed(std::unique_ptr<RasterBucket> result) {
|
||||
bucket = std::move(result);
|
||||
loaded = true;
|
||||
renderable = bucket ? true : false;
|
||||
@@ -65,6 +65,12 @@ Bucket* RasterTile::getBucket(const style::Layer::Impl&) const {
|
||||
return bucket.get();
|
||||
}
|
||||
|
||||
void RasterTile::setMask(TileMask&& mask) {
|
||||
if (bucket) {
|
||||
bucket->setMask(std::move(mask));
|
||||
}
|
||||
}
|
||||
|
||||
void RasterTile::setNecessity(Necessity necessity) {
|
||||
loader.setNecessity(necessity);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace mbgl {
|
||||
|
||||
class Tileset;
|
||||
class TileParameters;
|
||||
class RasterBucket;
|
||||
|
||||
namespace style {
|
||||
class Layer;
|
||||
@@ -33,7 +34,9 @@ public:
|
||||
void upload(gl::Context&) override;
|
||||
Bucket* getBucket(const style::Layer::Impl&) const override;
|
||||
|
||||
void onParsed(std::unique_ptr<Bucket> result);
|
||||
void setMask(TileMask&&) override;
|
||||
|
||||
void onParsed(std::unique_ptr<RasterBucket> result);
|
||||
void onError(std::exception_ptr);
|
||||
|
||||
private:
|
||||
@@ -44,7 +47,7 @@ private:
|
||||
|
||||
// Contains the Bucket object for the tile. Buckets are render
|
||||
// objects and they get added by tile parsing operations.
|
||||
std::unique_ptr<Bucket> bucket;
|
||||
std::unique_ptr<RasterBucket> bucket;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <mbgl/util/feature.hpp>
|
||||
#include <mbgl/util/tile_coordinate.hpp>
|
||||
#include <mbgl/tile/tile_id.hpp>
|
||||
#include <mbgl/renderer/tile_mask.hpp>
|
||||
#include <mbgl/renderer/bucket.hpp>
|
||||
#include <mbgl/tile/geometry_tile_data.hpp>
|
||||
#include <mbgl/storage/resource.hpp>
|
||||
@@ -54,6 +55,7 @@ public:
|
||||
|
||||
virtual void setPlacementConfig(const PlacementConfig&) {}
|
||||
virtual void setLayers(const std::vector<Immutable<style::Layer::Impl>>&) {}
|
||||
virtual void setMask(TileMask&&) {}
|
||||
|
||||
virtual void queryRenderedFeatures(
|
||||
std::unordered_map<std::string, std::vector<Feature>>& result,
|
||||
|
||||
@@ -12,6 +12,26 @@
|
||||
|
||||
#include <mbgl/map/mode.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
template <class Attributes>
|
||||
bool operator==(const Segment<Attributes>& lhs, const Segment<Attributes>& rhs) {
|
||||
return std::tie(lhs.vertexOffset, lhs.indexOffset, lhs.vertexLength, lhs.indexLength) ==
|
||||
std::tie(rhs.vertexOffset, rhs.indexOffset, rhs.vertexLength, rhs.indexLength);
|
||||
}
|
||||
|
||||
namespace gl {
|
||||
namespace detail {
|
||||
|
||||
template <class A1, class A2>
|
||||
bool operator==(const Vertex<A1, A2>& lhs, const Vertex<A1, A2>& rhs) {
|
||||
return std::tie(lhs.a1, lhs.a2) == std::tie(rhs.a1, rhs.a2);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace gl
|
||||
} // namespace mbgl
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
namespace {
|
||||
@@ -114,3 +134,142 @@ TEST(Buckets, RasterBucket) {
|
||||
bucket.clear();
|
||||
ASSERT_TRUE(bucket.needsUpload());
|
||||
}
|
||||
|
||||
TEST(Buckets, RasterBucketMaskEmpty) {
|
||||
RasterBucket bucket{ nullptr };
|
||||
bucket.setMask({});
|
||||
EXPECT_EQ((std::vector<RasterLayoutVertex>{}), bucket.vertices.vector());
|
||||
EXPECT_EQ((std::vector<uint16_t>{}), bucket.indices.vector());
|
||||
SegmentVector<RasterAttributes> expectedSegments;
|
||||
expectedSegments.emplace_back(0, 0, 0, 0);
|
||||
EXPECT_EQ(expectedSegments, bucket.segments);
|
||||
}
|
||||
|
||||
TEST(Buckets, RasterBucketMaskNoChildren) {
|
||||
RasterBucket bucket{ nullptr };
|
||||
bucket.setMask({ CanonicalTileID{ 0, 0, 0 } });
|
||||
|
||||
// A mask of 0/0/0 doesn't produce buffers since we're instead using the global shared buffers.
|
||||
EXPECT_EQ((std::vector<RasterLayoutVertex>{}), bucket.vertices.vector());
|
||||
EXPECT_EQ((std::vector<uint16_t>{}), bucket.indices.vector());
|
||||
EXPECT_EQ((SegmentVector<RasterAttributes>{}), bucket.segments);
|
||||
}
|
||||
|
||||
TEST(Buckets, RasterBucketMaskTwoChildren) {
|
||||
RasterBucket bucket{ nullptr };
|
||||
bucket.setMask(
|
||||
{ CanonicalTileID{ 1, 0, 0 }, CanonicalTileID{ 1, 1, 1 } });
|
||||
|
||||
EXPECT_EQ(
|
||||
(std::vector<RasterLayoutVertex>{
|
||||
// 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 }),
|
||||
}),
|
||||
bucket.vertices.vector());
|
||||
|
||||
EXPECT_EQ(
|
||||
(std::vector<uint16_t>{
|
||||
// 1/0/1
|
||||
0, 1, 2,
|
||||
1, 2, 3,
|
||||
|
||||
// 1/1/1
|
||||
4, 5, 6,
|
||||
5, 6, 7,
|
||||
}),
|
||||
bucket.indices.vector());
|
||||
|
||||
|
||||
SegmentVector<RasterAttributes> expectedSegments;
|
||||
expectedSegments.emplace_back(0, 0, 8, 12);
|
||||
EXPECT_EQ(expectedSegments, bucket.segments);
|
||||
}
|
||||
|
||||
TEST(Buckets, RasterBucketMaskComplex) {
|
||||
RasterBucket bucket{ nullptr };
|
||||
bucket.setMask(
|
||||
{ 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<RasterLayoutVertex>{
|
||||
// 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 }),
|
||||
}),
|
||||
bucket.vertices.vector());
|
||||
|
||||
EXPECT_EQ(
|
||||
(std::vector<uint16_t>{
|
||||
// 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,
|
||||
}),
|
||||
bucket.indices.vector());
|
||||
|
||||
|
||||
SegmentVector<RasterAttributes> expectedSegments;
|
||||
expectedSegments.emplace_back(0, 0, 24, 36);
|
||||
EXPECT_EQ(expectedSegments, bucket.segments);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user