diff options
Diffstat (limited to 'src/mbgl/renderer')
26 files changed, 550 insertions, 246 deletions
diff --git a/src/mbgl/renderer/buckets/circle_bucket.cpp b/src/mbgl/renderer/buckets/circle_bucket.cpp index 04126990b3..d23f0861f4 100644 --- a/src/mbgl/renderer/buckets/circle_bucket.cpp +++ b/src/mbgl/renderer/buckets/circle_bucket.cpp @@ -49,7 +49,7 @@ void CircleBucket::addFeature(const GeometryTileFeature& feature, // Do not include points that are outside the tile boundaries. // Include all points in Still mode. You need to include points from // neighbouring tiles so that they are not clipped at tile boundaries. - if ((mode != MapMode::Still) && + if ((mode == MapMode::Continuous) && (x < 0 || x >= util::EXTENT || y < 0 || y >= util::EXTENT)) continue; if (segments.empty() || segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) { diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp index a3f71f1f6e..60e8a0b504 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.cpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp @@ -16,10 +16,14 @@ SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layo const style::DataDrivenPropertyValue<float>& iconSize, float zoom, bool sdfIcons_, - bool iconsNeedLinear_) + bool iconsNeedLinear_, + bool sortFeaturesByY_, + const std::vector<SymbolInstance>&& symbolInstances_) : layout(std::move(layout_)), sdfIcons(sdfIcons_), iconsNeedLinear(iconsNeedLinear_ || iconSize.isDataDriven() || !iconSize.isZoomConstant()), + sortFeaturesByY(sortFeaturesByY_), + symbolInstances(std::move(symbolInstances_)), textSizeBinder(SymbolSizeBinder::create(zoom, textSize, TextSize::defaultValue())), iconSizeBinder(SymbolSizeBinder::create(zoom, iconSize, IconSize::defaultValue())) { @@ -36,28 +40,84 @@ SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layo void SymbolBucket::upload(gl::Context& context) { if (hasTextData()) { - text.vertexBuffer = context.createVertexBuffer(std::move(text.vertices)); - text.dynamicVertexBuffer = context.createVertexBuffer(std::move(text.dynamicVertices), gl::BufferUsage::StreamDraw); - text.indexBuffer = context.createIndexBuffer(std::move(text.triangles)); + if (!staticUploaded) { + text.indexBuffer = context.createIndexBuffer(std::move(text.triangles), sortFeaturesByY ? gl::BufferUsage::StreamDraw : gl::BufferUsage::StaticDraw); + text.vertexBuffer = context.createVertexBuffer(std::move(text.vertices)); + } else if (!sortUploaded) { + context.updateIndexBuffer(*text.indexBuffer, std::move(text.triangles)); + } + + if (!dynamicUploaded) { + text.dynamicVertexBuffer = context.createVertexBuffer(std::move(text.dynamicVertices), gl::BufferUsage::StreamDraw); + } + if (!placementChangesUploaded) { + if (!text.opacityVertexBuffer) { + text.opacityVertexBuffer = context.createVertexBuffer(std::move(text.opacityVertices), gl::BufferUsage::StreamDraw); + } else { + context.updateVertexBuffer(*text.opacityVertexBuffer, std::move(text.opacityVertices)); + } + } } if (hasIconData()) { - icon.vertexBuffer = context.createVertexBuffer(std::move(icon.vertices)); - icon.dynamicVertexBuffer = context.createVertexBuffer(std::move(icon.dynamicVertices), gl::BufferUsage::StreamDraw); - icon.indexBuffer = context.createIndexBuffer(std::move(icon.triangles)); + if (!staticUploaded) { + icon.indexBuffer = context.createIndexBuffer(std::move(icon.triangles), sortFeaturesByY ? gl::BufferUsage::StreamDraw : gl::BufferUsage::StaticDraw); + icon.vertexBuffer = context.createVertexBuffer(std::move(icon.vertices)); + } else if (!sortUploaded) { + context.updateIndexBuffer(*icon.indexBuffer, std::move(icon.triangles)); + } + if (!dynamicUploaded) { + icon.dynamicVertexBuffer = context.createVertexBuffer(std::move(icon.dynamicVertices), gl::BufferUsage::StreamDraw); + } + if (!placementChangesUploaded) { + if (!icon.opacityVertexBuffer) { + icon.opacityVertexBuffer = context.createVertexBuffer(std::move(icon.opacityVertices), gl::BufferUsage::StreamDraw); + } else { + context.updateVertexBuffer(*icon.opacityVertexBuffer, std::move(icon.opacityVertices)); + } + } } - if (!collisionBox.vertices.empty()) { - collisionBox.vertexBuffer = context.createVertexBuffer(std::move(collisionBox.vertices)); - collisionBox.indexBuffer = context.createIndexBuffer(std::move(collisionBox.lines)); + if (hasCollisionBoxData()) { + if (!staticUploaded) { + collisionBox.indexBuffer = context.createIndexBuffer(std::move(collisionBox.lines)); + collisionBox.vertexBuffer = context.createVertexBuffer(std::move(collisionBox.vertices)); + } + if (!placementChangesUploaded) { + if (!collisionBox.dynamicVertexBuffer) { + collisionBox.dynamicVertexBuffer = context.createVertexBuffer(std::move(collisionBox.dynamicVertices), gl::BufferUsage::StreamDraw); + } else { + context.updateVertexBuffer(*collisionBox.dynamicVertexBuffer, std::move(collisionBox.dynamicVertices)); + } + } } - - for (auto& pair : paintPropertyBinders) { - pair.second.first.upload(context); - pair.second.second.upload(context); + + if (hasCollisionCircleData()) { + if (!staticUploaded) { + collisionCircle.indexBuffer = context.createIndexBuffer(std::move(collisionCircle.triangles)); + collisionCircle.vertexBuffer = context.createVertexBuffer(std::move(collisionCircle.vertices)); + } + if (!placementChangesUploaded) { + if (!collisionCircle.dynamicVertexBuffer) { + collisionCircle.dynamicVertexBuffer = context.createVertexBuffer(std::move(collisionCircle.dynamicVertices), gl::BufferUsage::StreamDraw); + } else { + context.updateVertexBuffer(*collisionCircle.dynamicVertexBuffer, std::move(collisionCircle.dynamicVertices)); + } + } } + if (!staticUploaded) { + for (auto& pair : paintPropertyBinders) { + pair.second.first.upload(context); + pair.second.second.upload(context); + } + } + uploaded = true; + staticUploaded = true; + placementChangesUploaded = true; + dynamicUploaded = true; + sortUploaded = true; } bool SymbolBucket::hasData() const { @@ -76,4 +136,83 @@ bool SymbolBucket::hasCollisionBoxData() const { return !collisionBox.segments.empty(); } +bool SymbolBucket::hasCollisionCircleData() const { + return !collisionCircle.segments.empty(); +} + +void SymbolBucket::updateOpacity() { + placementChangesUploaded = false; + uploaded = false; +} + +void addPlacedSymbol(gl::IndexVector<gl::Triangles>& triangles, const PlacedSymbol& placedSymbol) { + auto endIndex = placedSymbol.vertexStartIndex + placedSymbol.glyphOffsets.size() * 4; + for (auto vertexIndex = placedSymbol.vertexStartIndex; vertexIndex < endIndex; vertexIndex += 4) { + triangles.emplace_back(vertexIndex + 0, vertexIndex + 1, vertexIndex + 2); + triangles.emplace_back(vertexIndex + 1, vertexIndex + 2, vertexIndex + 3); + } +} + +void SymbolBucket::sortFeatures(const float angle) { + if (!sortFeaturesByY) { + return; + } + + if (sortedAngle && *sortedAngle == angle) { + return; + } + + sortedAngle = angle; + + // The current approach to sorting doesn't sort across segments so don't try. + // Sorting within segments separately seemed not to be worth the complexity. + if (text.segments.size() > 1 || icon.segments.size() > 1) { + return; + } + + sortUploaded = false; + uploaded = false; + + // If the symbols are allowed to overlap sort them by their vertical screen position. + // The index array buffer is rewritten to reference the (unchanged) vertices in the + // sorted order. + + // To avoid sorting the actual symbolInstance array we sort an array of indexes. + std::vector<size_t> symbolInstanceIndexes; + symbolInstanceIndexes.reserve(symbolInstances.size()); + for (size_t i = 0; i < symbolInstances.size(); i++) { + symbolInstanceIndexes.push_back(i); + } + + const float sin = std::sin(angle); + const float cos = std::cos(angle); + + std::sort(symbolInstanceIndexes.begin(), symbolInstanceIndexes.end(), [sin, cos, this](size_t &aIndex, size_t &bIndex) { + const SymbolInstance& a = symbolInstances[aIndex]; + const SymbolInstance& b = symbolInstances[bIndex]; + const int32_t aRotated = sin * a.anchor.point.x + cos * a.anchor.point.y; + const int32_t bRotated = sin * b.anchor.point.x + cos * b.anchor.point.y; + return aRotated != bRotated ? + aRotated < bRotated : + a.index > b.index; + }); + + text.triangles.clear(); + icon.triangles.clear(); + + for (auto i : symbolInstanceIndexes) { + const SymbolInstance& symbolInstance = symbolInstances[i]; + + if (symbolInstance.placedTextIndex) { + addPlacedSymbol(text.triangles, text.placedSymbols[*symbolInstance.placedTextIndex]); + } + if (symbolInstance.placedVerticalTextIndex) { + addPlacedSymbol(text.triangles, text.placedSymbols[*symbolInstance.placedVerticalTextIndex]); + } + if (symbolInstance.placedIconIndex) { + addPlacedSymbol(icon.triangles, icon.placedSymbols[*symbolInstance.placedIconIndex]); + } + } +} + } // namespace mbgl diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp index 32f976bcb2..4abea90508 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.hpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp @@ -10,6 +10,7 @@ #include <mbgl/text/glyph_range.hpp> #include <mbgl/style/layers/symbol_layer_properties.hpp> #include <mbgl/layout/symbol_feature.hpp> +#include <mbgl/layout/symbol_instance.hpp> #include <vector> @@ -18,18 +19,22 @@ namespace mbgl { class PlacedSymbol { public: PlacedSymbol(Point<float> anchorPoint_, uint16_t segment_, float lowerSize_, float upperSize_, - std::array<float, 2> lineOffset_, float placementZoom_, bool useVerticalMode_, GeometryCoordinates line_) : + std::array<float, 2> lineOffset_, WritingModeType writingModes_, GeometryCoordinates line_, std::vector<float> tileDistances_) : anchorPoint(anchorPoint_), segment(segment_), lowerSize(lowerSize_), upperSize(upperSize_), - lineOffset(lineOffset_), placementZoom(placementZoom_), useVerticalMode(useVerticalMode_), line(std::move(line_)) {} + lineOffset(lineOffset_), writingModes(writingModes_), line(std::move(line_)), tileDistances(std::move(tileDistances_)), hidden(false), vertexStartIndex(0) + { + } Point<float> anchorPoint; uint16_t segment; float lowerSize; float upperSize; std::array<float, 2> lineOffset; - float placementZoom; - bool useVerticalMode; + WritingModeType writingModes; GeometryCoordinates line; + std::vector<float> tileDistances; std::vector<float> glyphOffsets; + bool hidden; + size_t vertexStartIndex; }; class SymbolBucket : public Bucket { @@ -40,17 +45,33 @@ public: const style::DataDrivenPropertyValue<float>& iconSize, float zoom, bool sdfIcons, - bool iconsNeedLinear); + bool iconsNeedLinear, + bool sortFeaturesByY, + const std::vector<SymbolInstance>&&); void upload(gl::Context&) override; bool hasData() const override; bool hasTextData() const; bool hasIconData() const; bool hasCollisionBoxData() const; + bool hasCollisionCircleData() const; + + void updateOpacity(); + void sortFeatures(const float angle); const style::SymbolLayoutProperties::PossiblyEvaluated layout; const bool sdfIcons; const bool iconsNeedLinear; + const bool sortFeaturesByY; + + optional<float> sortedAngle; + + bool staticUploaded = false; + bool placementChangesUploaded = false; + bool dynamicUploaded = false; + bool sortUploaded = false; + + std::vector<SymbolInstance> symbolInstances; std::map<std::string, std::pair< SymbolIconProgram::PaintPropertyBinders, @@ -61,12 +82,14 @@ public: struct TextBuffer { gl::VertexVector<SymbolLayoutVertex> vertices; gl::VertexVector<SymbolDynamicLayoutAttributes::Vertex> dynamicVertices; + gl::VertexVector<SymbolOpacityAttributes::Vertex> opacityVertices; gl::IndexVector<gl::Triangles> triangles; SegmentVector<SymbolTextAttributes> segments; std::vector<PlacedSymbol> placedSymbols; optional<gl::VertexBuffer<SymbolLayoutVertex>> vertexBuffer; optional<gl::VertexBuffer<SymbolDynamicLayoutAttributes::Vertex>> dynamicVertexBuffer; + optional<gl::VertexBuffer<SymbolOpacityAttributes::Vertex>> opacityVertexBuffer; optional<gl::IndexBuffer<gl::Triangles>> indexBuffer; } text; @@ -75,6 +98,7 @@ public: struct IconBuffer { gl::VertexVector<SymbolLayoutVertex> vertices; gl::VertexVector<SymbolDynamicLayoutAttributes::Vertex> dynamicVertices; + gl::VertexVector<SymbolOpacityAttributes::Vertex> opacityVertices; gl::IndexVector<gl::Triangles> triangles; SegmentVector<SymbolIconAttributes> segments; std::vector<PlacedSymbol> placedSymbols; @@ -82,18 +106,30 @@ public: optional<gl::VertexBuffer<SymbolLayoutVertex>> vertexBuffer; optional<gl::VertexBuffer<SymbolDynamicLayoutAttributes::Vertex>> dynamicVertexBuffer; + optional<gl::VertexBuffer<SymbolOpacityAttributes::Vertex>> opacityVertexBuffer; optional<gl::IndexBuffer<gl::Triangles>> indexBuffer; } icon; - struct CollisionBoxBuffer { - gl::VertexVector<CollisionBoxVertex> vertices; - gl::IndexVector<gl::Lines> lines; - SegmentVector<CollisionBoxAttributes> segments; + struct CollisionBuffer { + gl::VertexVector<CollisionBoxLayoutAttributes::Vertex> vertices; + gl::VertexVector<CollisionBoxDynamicAttributes::Vertex> dynamicVertices; + SegmentVector<CollisionBoxProgram::Attributes> segments; - optional<gl::VertexBuffer<CollisionBoxVertex>> vertexBuffer; - optional<gl::VertexBuffer<SymbolDynamicLayoutAttributes::Vertex>> dynamicVertexBuffer; + optional<gl::VertexBuffer<CollisionBoxLayoutAttributes::Vertex>> vertexBuffer; + optional<gl::VertexBuffer<CollisionBoxDynamicAttributes::Vertex>> dynamicVertexBuffer; + }; + + struct CollisionBoxBuffer : public CollisionBuffer { + gl::IndexVector<gl::Lines> lines; optional<gl::IndexBuffer<gl::Lines>> indexBuffer; } collisionBox; + + struct CollisionCircleBuffer : public CollisionBuffer { + gl::IndexVector<gl::Triangles> triangles; + optional<gl::IndexBuffer<gl::Triangles>> indexBuffer; + } collisionCircle; + + uint32_t bucketInstanceId = 0; }; } // namespace mbgl diff --git a/src/mbgl/renderer/frame_history.cpp b/src/mbgl/renderer/frame_history.cpp deleted file mode 100644 index de153b6963..0000000000 --- a/src/mbgl/renderer/frame_history.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include <mbgl/renderer/frame_history.hpp> -#include <mbgl/math/minmax.hpp> -#include <mbgl/gl/context.hpp> - -#include <cassert> - -namespace mbgl { - -FrameHistory::FrameHistory() { - changeOpacities.fill(0); - opacities.fill(0); -} - -void FrameHistory::record(const TimePoint& now, float zoom, const Duration& duration) { - - int16_t zoomIndex = std::floor(zoom * 10.0); - - if (firstFrame) { - changeTimes.fill(now); - - for (int16_t z = 0; z <= zoomIndex; z++) { - opacities.data[z] = 255u; - } - firstFrame = false; - } - - if (zoomIndex < previousZoomIndex) { - for (int16_t z = zoomIndex + 1; z <= previousZoomIndex; z++) { - changeTimes[z] = now; - changeOpacities[z] = opacities.data[z]; - } - } else { - for (int16_t z = zoomIndex; z > previousZoomIndex; z--) { - changeTimes[z] = now; - changeOpacities[z] = opacities.data[z]; - } - } - - for (int16_t z = 0; z <= 255; z++) { - const std::chrono::duration<float> timeDiff = now - changeTimes[z]; - const int32_t opacityChange = (duration == Milliseconds(0) ? 1 : (timeDiff / duration)) * 255; - const uint8_t opacity = z <= zoomIndex - ? util::min(255, changeOpacities[z] + opacityChange) - : util::max(0, changeOpacities[z] - opacityChange); - if (opacities.data[z] != opacity) { - opacities.data[z] = opacity; - dirty = true; - } - } - - if (zoomIndex != previousZoomIndex) { - previousZoomIndex = zoomIndex; - previousTime = now; - } - - time = now; -} - -bool FrameHistory::needsAnimation(const Duration& duration) const { - return (time - previousTime) < duration; -} - -void FrameHistory::upload(gl::Context& context, uint32_t unit) { - if (!texture) { - texture = context.createTexture(opacities, unit); - } else if (dirty) { - context.updateTexture(*texture, opacities, unit); - } - dirty = false; -} - -void FrameHistory::bind(gl::Context& context, uint32_t unit) { - upload(context, unit); - context.bindTexture(*texture, unit); -} - -bool FrameHistory::isVisible(const float zoom) const { - return opacities.data[std::floor(zoom * 10)] != 0; -} - -} // namespace mbgl diff --git a/src/mbgl/renderer/frame_history.hpp b/src/mbgl/renderer/frame_history.hpp deleted file mode 100644 index 75a8b60a71..0000000000 --- a/src/mbgl/renderer/frame_history.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include <array> - -#include <mbgl/util/platform.hpp> -#include <mbgl/gl/texture.hpp> -#include <mbgl/util/chrono.hpp> -#include <mbgl/util/image.hpp> -#include <mbgl/util/optional.hpp> - -namespace mbgl { - -namespace gl { -class Context; -} // namespace gl - -class FrameHistory { -public: - FrameHistory(); - void record(const TimePoint&, float zoom, const Duration&); - - bool needsAnimation(const Duration&) const; - void bind(gl::Context&, uint32_t); - void upload(gl::Context&, uint32_t); - bool isVisible(const float zoom) const; - -private: - std::array<TimePoint, 256> changeTimes; - std::array<uint8_t, 256> changeOpacities; - AlphaImage opacities{ { 256, 1 } }; - - int16_t previousZoomIndex = 0; - TimePoint previousTime; - TimePoint time; - bool firstFrame = true; - bool dirty = true; - - mbgl::optional<gl::Texture> texture; -}; - -} // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp index e7b022f3ee..fe2e7cd42d 100644 --- a/src/mbgl/renderer/layers/render_circle_layer.cpp +++ b/src/mbgl/renderer/layers/render_circle_layer.cpp @@ -63,7 +63,7 @@ void RenderCircleLayer::render(PaintParameters& parameters, RenderSource*) { parameters.context, gl::Triangles(), parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly), - parameters.mapMode == MapMode::Still + parameters.mapMode != MapMode::Continuous ? parameters.stencilModeForClipping(tile.clip) : gl::StencilMode::disabled(), parameters.colorModeForRenderPass(), diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 1376e8a3d8..04fcb2c3ab 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -4,7 +4,6 @@ #include <mbgl/renderer/property_evaluation_parameters.hpp> #include <mbgl/renderer/render_tile.hpp> #include <mbgl/renderer/paint_parameters.hpp> -#include <mbgl/renderer/frame_history.hpp> #include <mbgl/text/glyph_atlas.hpp> #include <mbgl/programs/programs.hpp> #include <mbgl/programs/symbol_program.hpp> @@ -81,8 +80,6 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { const auto& layout = bucket.layout; - parameters.frameHistory.bind(parameters.context, 1); - auto draw = [&] (auto& program, auto&& uniformValues, const auto& buffers, @@ -91,22 +88,18 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { const auto& binders, const auto& paintProperties) { - // We clip symbols to their tile extent in still mode. - const bool needsClipping = parameters.mapMode == MapMode::Still; - program.get(paintProperties).draw( parameters.context, gl::Triangles(), values_.pitchAlignment == AlignmentType::Map ? parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly) : gl::DepthMode::disabled(), - needsClipping - ? parameters.stencilModeForClipping(tile.clip) - : gl::StencilMode::disabled(), + gl::StencilMode::disabled(), parameters.colorModeForRenderPass(), std::move(uniformValues), *buffers.vertexBuffer, *buffers.dynamicVertexBuffer, + *buffers.opacityVertexBuffer, *symbolSizeBinder, *buffers.indexBuffer, buffers.segments, @@ -134,8 +127,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { values, tile, *bucket.iconSizeBinder, - parameters.state, - parameters.frameHistory); + parameters.state); parameters.context.updateVertexBuffer(*bucket.icon.dynamicVertexBuffer, std::move(bucket.icon.dynamicVertices)); } @@ -152,7 +144,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { if (bucket.sdfIcons) { if (values.hasHalo) { draw(parameters.programs.symbolIconSDF, - SymbolSDFIconProgram::uniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, SymbolSDFPart::Halo), + SymbolSDFIconProgram::uniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo), bucket.icon, bucket.iconSizeBinder, values, @@ -162,7 +154,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { if (values.hasFill) { draw(parameters.programs.symbolIconSDF, - SymbolSDFIconProgram::uniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, SymbolSDFPart::Fill), + SymbolSDFIconProgram::uniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill), bucket.icon, bucket.iconSizeBinder, values, @@ -171,7 +163,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { } } else { draw(parameters.programs.symbolIcon, - SymbolIconProgram::uniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state), + SymbolIconProgram::uniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange), bucket.icon, bucket.iconSizeBinder, values, @@ -196,8 +188,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { values, tile, *bucket.textSizeBinder, - parameters.state, - parameters.frameHistory); + parameters.state); parameters.context.updateVertexBuffer(*bucket.text.dynamicVertexBuffer, std::move(bucket.text.dynamicVertices)); } @@ -206,7 +197,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { if (values.hasHalo) { draw(parameters.programs.symbolGlyph, - SymbolSDFTextProgram::uniformValues(true, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, SymbolSDFPart::Halo), + SymbolSDFTextProgram::uniformValues(true, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo), bucket.text, bucket.textSizeBinder, values, @@ -216,7 +207,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { if (values.hasFill) { draw(parameters.programs.symbolGlyph, - SymbolSDFTextProgram::uniformValues(true, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, SymbolSDFPart::Fill), + SymbolSDFTextProgram::uniformValues(true, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill), bucket.text, bucket.textSizeBinder, values, @@ -229,23 +220,27 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { static const style::Properties<>::PossiblyEvaluated properties {}; static const CollisionBoxProgram::PaintPropertyBinders paintAttributeData(properties, 0); + auto pixelRatio = tile.id.pixelsToTileUnits(1, parameters.state.getZoom()); + auto scale = std::pow(2.0f, float(parameters.state.getZoom() - tile.tile.id.overscaledZ)); + std::array<float,2> extrudeScale = + {{ + parameters.pixelsToGLUnits[0] / (pixelRatio * scale), + parameters.pixelsToGLUnits[1] / (pixelRatio * scale) + + }}; parameters.programs.collisionBox.draw( parameters.context, gl::Lines { 1.0f }, gl::DepthMode::disabled(), - parameters.stencilModeForClipping(tile.clip), + gl::StencilMode::disabled(), parameters.colorModeForRenderPass(), CollisionBoxProgram::UniformValues { uniforms::u_matrix::Value{ tile.matrix }, - uniforms::u_scale::Value{ std::pow(2.0f, float(parameters.state.getZoom() - tile.tile.id.overscaledZ)) }, - uniforms::u_zoom::Value{ float(parameters.state.getZoom() * 10) }, - uniforms::u_maxzoom::Value{ float((tile.id.canonical.z + 1) * 10) }, - uniforms::u_collision_y_stretch::Value{ tile.tile.yStretch() }, - uniforms::u_camera_to_center_distance::Value{ parameters.state.getCameraToCenterDistance() }, - uniforms::u_pitch::Value{ parameters.state.getPitch() }, - uniforms::u_fadetexture::Value{ 1 } + uniforms::u_extrude_scale::Value{ extrudeScale }, + uniforms::u_camera_to_center_distance::Value{ parameters.state.getCameraToCenterDistance() } }, *bucket.collisionBox.vertexBuffer, + *bucket.collisionBox.dynamicVertexBuffer, *bucket.collisionBox.indexBuffer, bucket.collisionBox.segments, paintAttributeData, @@ -254,6 +249,41 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { getID() ); } + if (bucket.hasCollisionCircleData()) { + static const style::Properties<>::PossiblyEvaluated properties {}; + static const CollisionBoxProgram::PaintPropertyBinders paintAttributeData(properties, 0); + + auto pixelRatio = tile.id.pixelsToTileUnits(1, parameters.state.getZoom()); + auto scale = std::pow(2.0f, float(parameters.state.getZoom() - tile.tile.id.overscaledZ)); + std::array<float,2> extrudeScale = + {{ + parameters.pixelsToGLUnits[0] / (pixelRatio * scale), + parameters.pixelsToGLUnits[1] / (pixelRatio * scale) + + }}; + + parameters.programs.collisionCircle.draw( + parameters.context, + gl::Triangles(), + gl::DepthMode::disabled(), + gl::StencilMode::disabled(), + parameters.colorModeForRenderPass(), + CollisionBoxProgram::UniformValues { + uniforms::u_matrix::Value{ tile.matrix }, + uniforms::u_extrude_scale::Value{ extrudeScale }, + uniforms::u_camera_to_center_distance::Value{ parameters.state.getCameraToCenterDistance() } + }, + *bucket.collisionCircle.vertexBuffer, + *bucket.collisionCircle.dynamicVertexBuffer, + *bucket.collisionCircle.indexBuffer, + bucket.collisionCircle.segments, + paintAttributeData, + properties, + parameters.state.getZoom(), + getID() + ); + + } } } diff --git a/src/mbgl/renderer/paint_parameters.cpp b/src/mbgl/renderer/paint_parameters.cpp index 299db844bc..58dd5597a5 100644 --- a/src/mbgl/renderer/paint_parameters.cpp +++ b/src/mbgl/renderer/paint_parameters.cpp @@ -12,7 +12,6 @@ PaintParameters::PaintParameters(gl::Context& context_, const UpdateParameters& updateParameters, const EvaluatedLight& evaluatedLight_, RenderStaticData& staticData_, - FrameHistory& frameHistory_, ImageManager& imageManager_, LineAtlas& lineAtlas_) : context(context_), @@ -20,7 +19,6 @@ PaintParameters::PaintParameters(gl::Context& context_, state(updateParameters.transformState), evaluatedLight(evaluatedLight_), staticData(staticData_), - frameHistory(frameHistory_), imageManager(imageManager_), lineAtlas(lineAtlas_), mapMode(updateParameters.mode), diff --git a/src/mbgl/renderer/paint_parameters.hpp b/src/mbgl/renderer/paint_parameters.hpp index 60f5af4e9a..5c934c2239 100644 --- a/src/mbgl/renderer/paint_parameters.hpp +++ b/src/mbgl/renderer/paint_parameters.hpp @@ -17,7 +17,6 @@ namespace mbgl { class RendererBackend; class UpdateParameters; class RenderStaticData; -class FrameHistory; class Programs; class TransformState; class ImageManager; @@ -33,7 +32,6 @@ public: const UpdateParameters&, const EvaluatedLight&, RenderStaticData&, - FrameHistory&, ImageManager&, LineAtlas&); @@ -44,7 +42,6 @@ public: const EvaluatedLight& evaluatedLight; RenderStaticData& staticData; - FrameHistory& frameHistory; ImageManager& imageManager; LineAtlas& lineAtlas; @@ -74,6 +71,8 @@ public: uint32_t currentLayer; float depthRangeSize; const float depthEpsilon = 1.0f / (1 << 16); + + float symbolFadeChange; }; } // namespace mbgl diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp index dfc6bcf2fd..55831cb72c 100644 --- a/src/mbgl/renderer/render_layer.hpp +++ b/src/mbgl/renderer/render_layer.hpp @@ -82,13 +82,16 @@ public: friend std::string layoutKey(const RenderLayer&); protected: + // renderTiles are exposed directly to CrossTileSymbolIndex and Placement so they + // can update opacities in the symbol buckets immediately before rendering + friend class CrossTileSymbolIndex; + friend class Placement; + // Stores current set of tiles to be rendered for this layer. + std::vector<std::reference_wrapper<RenderTile>> renderTiles; + // Stores what render passes this layer is currently enabled for. This depends on the // evaluated StyleProperties object and is updated accordingly. RenderPass passes = RenderPass::None; - - //Stores current set of tiles to be rendered for this layer. - std::vector<std::reference_wrapper<RenderTile>> renderTiles; - }; } // namespace mbgl diff --git a/src/mbgl/renderer/render_source.cpp b/src/mbgl/renderer/render_source.cpp index 7723a1c7ca..6624bb7d96 100644 --- a/src/mbgl/renderer/render_source.cpp +++ b/src/mbgl/renderer/render_source.cpp @@ -6,6 +6,7 @@ #include <mbgl/renderer/tile_parameters.hpp> #include <mbgl/annotation/render_annotation_source.hpp> #include <mbgl/renderer/sources/render_image_source.hpp> +#include <mbgl/renderer/sources/render_custom_geometry_source.hpp> #include <mbgl/tile/tile.hpp> namespace mbgl { @@ -27,6 +28,8 @@ std::unique_ptr<RenderSource> RenderSource::create(Immutable<Source::Impl> impl) return std::make_unique<RenderAnnotationSource>(staticImmutableCast<AnnotationSource::Impl>(impl)); case SourceType::Image: return std::make_unique<RenderImageSource>(staticImmutableCast<ImageSource::Impl>(impl)); + case SourceType::CustomVector: + return std::make_unique<RenderCustomGeometrySource>(staticImmutableCast<CustomGeometrySource::Impl>(impl)); } // Not reachable, but placate GCC. diff --git a/src/mbgl/renderer/render_source.hpp b/src/mbgl/renderer/render_source.hpp index 8293923ff6..8c84af4f1e 100644 --- a/src/mbgl/renderer/render_source.hpp +++ b/src/mbgl/renderer/render_source.hpp @@ -24,6 +24,7 @@ class SourceQueryOptions; class Tile; class RenderSourceObserver; class TileParameters; +class CollisionIndex; class RenderSource : protected TileObserver { public: @@ -63,7 +64,8 @@ public: queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, const std::vector<const RenderLayer*>& layers, - const RenderedQueryOptions& options) const = 0; + const RenderedQueryOptions& options, + const CollisionIndex& collisionIndex) const = 0; virtual std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const = 0; diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index 5987e69374..aa138df662 100644 --- a/src/mbgl/renderer/renderer_impl.cpp +++ b/src/mbgl/renderer/renderer_impl.cpp @@ -56,7 +56,8 @@ Renderer::Impl::Impl(RendererBackend& backend_, , imageImpls(makeMutable<std::vector<Immutable<style::Image::Impl>>>()) , sourceImpls(makeMutable<std::vector<Immutable<style::Source::Impl>>>()) , layerImpls(makeMutable<std::vector<Immutable<style::Layer::Impl>>>()) - , renderLight(makeMutable<Light::Impl>()) { + , renderLight(makeMutable<Light::Impl>()) + , placement(std::make_unique<Placement>(TransformState{}, MapMode::Static)) { glyphManager->setObserver(this); } @@ -80,7 +81,7 @@ void Renderer::Impl::setObserver(RendererObserver* observer_) { } void Renderer::Impl::render(const UpdateParameters& updateParameters) { - if (updateParameters.mode == MapMode::Still) { + if (updateParameters.mode != MapMode::Continuous) { // Don't load/render anyting in still mode until explicitly requested. if (!updateParameters.stillImageRequest) { return; @@ -252,13 +253,12 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { updateParameters, renderLight.getEvaluated(), *staticData, - frameHistory, *imageManager, *lineAtlas }; bool loaded = updateParameters.styleLoaded && isLoaded(); - if (updateParameters.mode == MapMode::Still && !loaded) { + if (updateParameters.mode != MapMode::Continuous && !loaded) { return; } @@ -334,11 +334,15 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { auto par = util::rotate(pa, parameters.state.getAngle()); auto pbr = util::rotate(pb, parameters.state.getAngle()); - return std::tie(par.y, par.x) < std::tie(pbr.y, pbr.x); + return std::tie(b.id.canonical.z, par.y, par.x) < std::tie(a.id.canonical.z, pbr.y, pbr.x); }); } else { std::sort(sortedTiles.begin(), sortedTiles.end(), [](const auto& a, const auto& b) { return a.get().id < b.get().id; }); + // Don't render non-symbol layers for tiles that we're only holding on to for symbol fading + sortedTiles.erase(std::remove_if(sortedTiles.begin(), sortedTiles.end(), + [](const auto& tile) { return tile.get().tile.holdForFade(); }), + sortedTiles.end()); } std::vector<std::reference_wrapper<RenderTile>> sortedTilesForInsertion; @@ -348,35 +352,13 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { continue; } - // We're not clipping symbol layers, so when we have both parents and children of symbol - // layers, we drop all children in favor of their parent to avoid duplicate labels. - // See https://github.com/mapbox/mapbox-gl-native/issues/2482 - if (symbolLayer) { - bool skip = false; - // Look back through the buckets we decided to render to find out whether there is - // already a bucket from this layer that is a parent of this tile. Tiles are ordered - // by zoom level when we obtain them from getTiles(). - for (auto it = sortedTilesForInsertion.rbegin(); - it != sortedTilesForInsertion.rend(); ++it) { - if (tile.tile.id.isChildOf(it->get().tile.id)) { - skip = true; - break; - } - } - if (skip) { - continue; - } - } - auto bucket = tile.tile.getBucket(*layer->baseImpl); if (bucket) { sortedTilesForInsertion.emplace_back(tile); tile.used = true; - // We only need clipping when we're _not_ drawing a symbol layer. The only exception - // for symbol layers is when we're rendering still images. See render_symbol_layer.cpp - // for the exception we make there. - if (!symbolLayer || parameters.mapMode == MapMode::Still) { + // We only need clipping when we're _not_ drawing a symbol layer. + if (!symbolLayer) { tile.needsClipping = true; } } @@ -385,9 +367,47 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { order.emplace_back(RenderItem { *layer, source }); } - frameHistory.record(parameters.timePoint, - parameters.state.getZoom(), - parameters.mapMode == MapMode::Continuous ? util::DEFAULT_TRANSITION_DURATION : Milliseconds(0)); + bool symbolBucketsChanged = false; + if (parameters.mapMode != MapMode::Continuous) { + // TODO: Think about right way for symbol index to handle still rendering + crossTileSymbolIndex.reset(); + } + for (auto it = order.rbegin(); it != order.rend(); ++it) { + if (it->layer.is<RenderSymbolLayer>()) { + if (crossTileSymbolIndex.addLayer(*it->layer.as<RenderSymbolLayer>())) symbolBucketsChanged = true; + } + } + + bool placementChanged = false; + if (!placement->stillRecent(parameters.timePoint)) { + auto newPlacement = std::make_unique<Placement>(parameters.state, parameters.mapMode); + for (auto it = order.rbegin(); it != order.rend(); ++it) { + if (it->layer.is<RenderSymbolLayer>()) { + newPlacement->placeLayer(*it->layer.as<RenderSymbolLayer>(), parameters.projMatrix, parameters.debugOptions & MapDebugOptions::Collision); + } + } + + placementChanged = newPlacement->commit(*placement, parameters.timePoint); + if (placementChanged || symbolBucketsChanged) { + placement = std::move(newPlacement); + } + + placement->setRecent(parameters.timePoint); + + updateFadingTiles(); + } else { + placement->setStale(); + } + + parameters.symbolFadeChange = placement->symbolFadeChange(parameters.timePoint); + + if (placementChanged || symbolBucketsChanged) { + for (auto it = order.rbegin(); it != order.rend(); ++it) { + if (it->layer.is<RenderSymbolLayer>()) { + placement->updateLayerOpacities(*it->layer.as<RenderSymbolLayer>()); + } + } + } // - UPLOAD PASS ------------------------------------------------------------------------------- // Uploads all required buffers and images before we do any actual rendering. @@ -396,8 +416,7 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { parameters.imageManager.upload(parameters.context, 0); parameters.lineAtlas.upload(parameters.context, 0); - parameters.frameHistory.upload(parameters.context, 0); - + // Update all clipping IDs + upload buckets. for (const auto& entry : renderSources) { if (entry.second->isEnabled()) { @@ -607,7 +626,7 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { observer->onDidFinishRenderingFrame( loaded ? RendererObserver::RenderMode::Full : RendererObserver::RenderMode::Partial, - updateParameters.mode == MapMode::Continuous && (hasTransitions() || frameHistory.needsAnimation(util::DEFAULT_TRANSITION_DURATION)) + updateParameters.mode == MapMode::Continuous && hasTransitions(parameters.timePoint) ); if (!loaded) { @@ -647,7 +666,7 @@ std::vector<Feature> Renderer::Impl::queryRenderedFeatures(const ScreenLineStrin std::unordered_map<std::string, std::vector<Feature>> resultsByLayer; for (const auto& sourceID : sourceIDs) { if (RenderSource* renderSource = getRenderSource(sourceID)) { - auto sourceResults = renderSource->queryRenderedFeatures(geometry, transformState, layers, options); + auto sourceResults = renderSource->queryRenderedFeatures(geometry, transformState, layers, options, placement->getCollisionIndex()); std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin())); } } @@ -727,7 +746,7 @@ RenderSource* Renderer::Impl::getRenderSource(const std::string& id) const { return it != renderSources.end() ? it->second.get() : nullptr; } -bool Renderer::Impl::hasTransitions() const { +bool Renderer::Impl::hasTransitions(TimePoint timePoint) const { if (renderLight.hasTransition()) { return true; } @@ -738,9 +757,30 @@ bool Renderer::Impl::hasTransitions() const { } } + if (placement->hasTransitions(timePoint)) { + return true; + } + + if (fadingTiles) { + return true; + } + return false; } +void Renderer::Impl::updateFadingTiles() { + fadingTiles = false; + for (auto& source : renderSources) { + for (auto& renderTile : source.second->getRenderTiles()) { + Tile& tile = renderTile.get().tile; + if (tile.holdForFade()) { + fadingTiles = true; + tile.performedFadePlacement(); + } + } + } +} + bool Renderer::Impl::isLoaded() const { for (const auto& entry: renderSources) { if (!entry.second->isLoaded()) { diff --git a/src/mbgl/renderer/renderer_impl.hpp b/src/mbgl/renderer/renderer_impl.hpp index 720e01ed53..4f8139791c 100644 --- a/src/mbgl/renderer/renderer_impl.hpp +++ b/src/mbgl/renderer/renderer_impl.hpp @@ -4,13 +4,14 @@ #include <mbgl/renderer/renderer.hpp> #include <mbgl/renderer/render_source_observer.hpp> #include <mbgl/renderer/render_light.hpp> -#include <mbgl/renderer/frame_history.hpp> #include <mbgl/style/image.hpp> #include <mbgl/style/source.hpp> #include <mbgl/style/layer.hpp> #include <mbgl/map/transform_state.hpp> #include <mbgl/map/zoom_history.hpp> +#include <mbgl/text/cross_tile_symbol_index.hpp> #include <mbgl/text/glyph_manager_observer.hpp> +#include <mbgl/text/placement.hpp> #include <memory> #include <string> @@ -31,6 +32,7 @@ class Scheduler; class GlyphManager; class ImageManager; class LineAtlas; +class CrossTileSymbolIndex; class Renderer::Impl : public GlyphManagerObserver, public RenderSourceObserver{ @@ -56,7 +58,7 @@ public: private: bool isLoaded() const; - bool hasTransitions() const; + bool hasTransitions(TimePoint) const; RenderSource* getRenderSource(const std::string& id) const; @@ -72,6 +74,8 @@ private: void onTileChanged(RenderSource&, const OverscaledTileID&) override; void onTileError(RenderSource&, const OverscaledTileID&, std::exception_ptr) override; + void updateFadingTiles(); + friend class Renderer; RendererBackend& backend; @@ -91,7 +95,6 @@ private: }; RenderState renderState = RenderState::Never; - FrameHistory frameHistory; ZoomHistory zoomHistory; TransformState transformState; @@ -108,7 +111,11 @@ private: std::unordered_map<std::string, std::unique_ptr<RenderLayer>> renderLayers; RenderLight renderLight; + CrossTileSymbolIndex crossTileSymbolIndex; + std::unique_ptr<Placement> placement; + bool contextLost = false; + bool fadingTiles = false; }; } // namespace mbgl diff --git a/src/mbgl/renderer/sources/render_custom_geometry_source.cpp b/src/mbgl/renderer/sources/render_custom_geometry_source.cpp new file mode 100644 index 0000000000..111f0234ed --- /dev/null +++ b/src/mbgl/renderer/sources/render_custom_geometry_source.cpp @@ -0,0 +1,86 @@ +#include <mbgl/renderer/sources/render_custom_geometry_source.hpp> +#include <mbgl/renderer/render_tile.hpp> +#include <mbgl/renderer/paint_parameters.hpp> +#include <mbgl/tile/custom_geometry_tile.hpp> + +#include <mbgl/algorithm/generate_clip_ids.hpp> +#include <mbgl/algorithm/generate_clip_ids_impl.hpp> + +namespace mbgl { + +using namespace style; + +RenderCustomGeometrySource::RenderCustomGeometrySource(Immutable<style::CustomGeometrySource::Impl> impl_) + : RenderSource(impl_) { + tilePyramid.setObserver(this); +} + +const style::CustomGeometrySource::Impl& RenderCustomGeometrySource::impl() const { + return static_cast<const style::CustomGeometrySource::Impl&>(*baseImpl); +} + +bool RenderCustomGeometrySource::isLoaded() const { + return tilePyramid.isLoaded(); +} + +void RenderCustomGeometrySource::update(Immutable<style::Source::Impl> baseImpl_, + const std::vector<Immutable<Layer::Impl>>& layers, + const bool needsRendering, + const bool needsRelayout, + const TileParameters& parameters) { + std::swap(baseImpl, baseImpl_); + + enabled = needsRendering; + + auto tileLoader = impl().getTileLoader(); + if (!tileLoader) { + return; + } + + tilePyramid.update(layers, + needsRendering, + needsRelayout, + parameters, + SourceType::CustomVector, + util::tileSize, + impl().getZoomRange(), + [&] (const OverscaledTileID& tileID) { + return std::make_unique<CustomGeometryTile>(tileID, impl().id, parameters, impl().getTileOptions(), *tileLoader); + }); +} + +void RenderCustomGeometrySource::startRender(PaintParameters& parameters) { + parameters.clipIDGenerator.update(tilePyramid.getRenderTiles()); + tilePyramid.startRender(parameters); +} + +void RenderCustomGeometrySource::finishRender(PaintParameters& parameters) { + tilePyramid.finishRender(parameters); +} + +std::vector<std::reference_wrapper<RenderTile>> RenderCustomGeometrySource::getRenderTiles() { + return tilePyramid.getRenderTiles(); +} + +std::unordered_map<std::string, std::vector<Feature>> +RenderCustomGeometrySource::queryRenderedFeatures(const ScreenLineString& geometry, + const TransformState& transformState, + const std::vector<const RenderLayer*>& layers, + const RenderedQueryOptions& options, + const CollisionIndex& collisionIndex) const { + return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options, collisionIndex); +} + +std::vector<Feature> RenderCustomGeometrySource::querySourceFeatures(const SourceQueryOptions& options) const { + return tilePyramid.querySourceFeatures(options); +} + +void RenderCustomGeometrySource::onLowMemory() { + tilePyramid.onLowMemory(); +} + +void RenderCustomGeometrySource::dumpDebugLogs() const { + tilePyramid.dumpDebugLogs(); +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/sources/render_custom_geometry_source.hpp b/src/mbgl/renderer/sources/render_custom_geometry_source.hpp new file mode 100644 index 0000000000..82e691d5c9 --- /dev/null +++ b/src/mbgl/renderer/sources/render_custom_geometry_source.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include <mbgl/renderer/render_source.hpp> +#include <mbgl/renderer/tile_pyramid.hpp> +#include <mbgl/style/sources/custom_geometry_source_impl.hpp> + +namespace mbgl { + +class RenderCustomGeometrySource : public RenderSource { +public: + RenderCustomGeometrySource(Immutable<style::CustomGeometrySource::Impl>); + + bool isLoaded() const final; + + void update(Immutable<style::Source::Impl>, + const std::vector<Immutable<style::Layer::Impl>>&, + bool needsRendering, + bool needsRelayout, + const TileParameters&) final; + + void startRender(PaintParameters&) final; + void finishRender(PaintParameters&) final; + + std::vector<std::reference_wrapper<RenderTile>> getRenderTiles() final; + + std::unordered_map<std::string, std::vector<Feature>> + queryRenderedFeatures(const ScreenLineString& geometry, + const TransformState& transformState, + const std::vector<const RenderLayer*>& layers, + const RenderedQueryOptions& options, + const CollisionIndex& collisionIndex) const final; + + std::vector<Feature> + querySourceFeatures(const SourceQueryOptions&) const final; + + void onLowMemory() final; + void dumpDebugLogs() const final; + +private: + const style::CustomGeometrySource::Impl& impl() const; + + TilePyramid tilePyramid; +}; + +template <> +inline bool RenderSource::is<RenderCustomGeometrySource>() const { + return baseImpl->type == style::SourceType::CustomVector; +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/sources/render_geojson_source.cpp b/src/mbgl/renderer/sources/render_geojson_source.cpp index 504db78ea3..d07cfcdc41 100644 --- a/src/mbgl/renderer/sources/render_geojson_source.cpp +++ b/src/mbgl/renderer/sources/render_geojson_source.cpp @@ -84,8 +84,9 @@ std::unordered_map<std::string, std::vector<Feature>> RenderGeoJSONSource::queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, const std::vector<const RenderLayer*>& layers, - const RenderedQueryOptions& options) const { - return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options); + const RenderedQueryOptions& options, + const CollisionIndex& collisionIndex) const { + return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options, collisionIndex); } std::vector<Feature> RenderGeoJSONSource::querySourceFeatures(const SourceQueryOptions& options) const { diff --git a/src/mbgl/renderer/sources/render_geojson_source.hpp b/src/mbgl/renderer/sources/render_geojson_source.hpp index b2e06c68d4..55166ea901 100644 --- a/src/mbgl/renderer/sources/render_geojson_source.hpp +++ b/src/mbgl/renderer/sources/render_geojson_source.hpp @@ -31,7 +31,8 @@ public: queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, const std::vector<const RenderLayer*>& layers, - const RenderedQueryOptions& options) const final; + const RenderedQueryOptions& options, + const CollisionIndex&) const final; std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const final; diff --git a/src/mbgl/renderer/sources/render_image_source.cpp b/src/mbgl/renderer/sources/render_image_source.cpp index 9140e01711..b5c42584e0 100644 --- a/src/mbgl/renderer/sources/render_image_source.cpp +++ b/src/mbgl/renderer/sources/render_image_source.cpp @@ -84,7 +84,8 @@ std::unordered_map<std::string, std::vector<Feature>> RenderImageSource::queryRenderedFeatures(const ScreenLineString&, const TransformState&, const std::vector<const RenderLayer*>&, - const RenderedQueryOptions&) const { + const RenderedQueryOptions&, + const CollisionIndex&) const { return std::unordered_map<std::string, std::vector<Feature>> {}; } diff --git a/src/mbgl/renderer/sources/render_image_source.hpp b/src/mbgl/renderer/sources/render_image_source.hpp index 8d80838c3b..72cf4cea61 100644 --- a/src/mbgl/renderer/sources/render_image_source.hpp +++ b/src/mbgl/renderer/sources/render_image_source.hpp @@ -32,7 +32,8 @@ public: queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, const std::vector<const RenderLayer*>& layers, - const RenderedQueryOptions& options) const final; + const RenderedQueryOptions& options, + const CollisionIndex& collisionIndex) const final; std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const final; diff --git a/src/mbgl/renderer/sources/render_raster_source.cpp b/src/mbgl/renderer/sources/render_raster_source.cpp index bcd719365d..f11f9b7aed 100644 --- a/src/mbgl/renderer/sources/render_raster_source.cpp +++ b/src/mbgl/renderer/sources/render_raster_source.cpp @@ -74,7 +74,8 @@ std::unordered_map<std::string, std::vector<Feature>> RenderRasterSource::queryRenderedFeatures(const ScreenLineString&, const TransformState&, const std::vector<const RenderLayer*>&, - const RenderedQueryOptions&) const { + const RenderedQueryOptions&, + const CollisionIndex& ) const { return std::unordered_map<std::string, std::vector<Feature>> {}; } diff --git a/src/mbgl/renderer/sources/render_raster_source.hpp b/src/mbgl/renderer/sources/render_raster_source.hpp index e1bf5798ff..25041fde43 100644 --- a/src/mbgl/renderer/sources/render_raster_source.hpp +++ b/src/mbgl/renderer/sources/render_raster_source.hpp @@ -27,7 +27,8 @@ public: queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, const std::vector<const RenderLayer*>& layers, - const RenderedQueryOptions& options) const final; + const RenderedQueryOptions& options, + const CollisionIndex& collisionIndex) const final; std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const final; diff --git a/src/mbgl/renderer/sources/render_vector_source.cpp b/src/mbgl/renderer/sources/render_vector_source.cpp index ca3071c6b0..49f8fdff2c 100644 --- a/src/mbgl/renderer/sources/render_vector_source.cpp +++ b/src/mbgl/renderer/sources/render_vector_source.cpp @@ -77,8 +77,9 @@ std::unordered_map<std::string, std::vector<Feature>> RenderVectorSource::queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, const std::vector<const RenderLayer*>& layers, - const RenderedQueryOptions& options) const { - return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options); + const RenderedQueryOptions& options, + const CollisionIndex& collisionIndex) const { + return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options, collisionIndex); } std::vector<Feature> RenderVectorSource::querySourceFeatures(const SourceQueryOptions& options) const { diff --git a/src/mbgl/renderer/sources/render_vector_source.hpp b/src/mbgl/renderer/sources/render_vector_source.hpp index ac319a167e..4a992e854f 100644 --- a/src/mbgl/renderer/sources/render_vector_source.hpp +++ b/src/mbgl/renderer/sources/render_vector_source.hpp @@ -27,7 +27,8 @@ public: queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, const std::vector<const RenderLayer*>& layers, - const RenderedQueryOptions& options) const final; + const RenderedQueryOptions& options, + const CollisionIndex& collisionIndex) const final; std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const final; diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp index 3e2311089d..c1566d12a5 100644 --- a/src/mbgl/renderer/tile_pyramid.cpp +++ b/src/mbgl/renderer/tile_pyramid.cpp @@ -5,7 +5,6 @@ #include <mbgl/renderer/tile_parameters.hpp> #include <mbgl/renderer/query.hpp> #include <mbgl/map/transform.hpp> -#include <mbgl/text/placement_config.hpp> #include <mbgl/math/clamp.hpp> #include <mbgl/util/tile_cover.hpp> #include <mbgl/util/enum.hpp> @@ -120,6 +119,7 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer // use because they're still loading. In addition to that, we also need to retain all tiles that // we're actively using, e.g. as a replacement for tile that aren't loaded yet. std::set<OverscaledTileID> retain; + std::set<UnwrappedTileID> rendered; auto retainTileFn = [&](Tile& tile, TileNecessity necessity) -> void { if (retain.emplace(tile.id).second) { @@ -148,8 +148,17 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer } return tiles.emplace(tileID, std::move(tile)).first->second.get(); }; + + std::map<UnwrappedTileID, Tile*> previouslyRenderedTiles; + for (auto& renderTile : renderTiles) { + previouslyRenderedTiles[renderTile.id] = &renderTile.tile; + } + auto renderTileFn = [&](const UnwrappedTileID& tileID, Tile& tile) { renderTiles.emplace_back(tileID, tile); + rendered.emplace(tileID); + previouslyRenderedTiles.erase(tileID); // Still rendering this tile, no need for special fading logic. + tile.markRenderedIdeal(); }; renderTiles.clear(); @@ -161,6 +170,18 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer algorithm::updateRenderables(getTileFn, createTileFn, retainTileFn, renderTileFn, idealTiles, zoomRange, tileZoom); + + for (auto previouslyRenderedTile : previouslyRenderedTiles) { + Tile& tile = *previouslyRenderedTile.second; + tile.markRenderedPreviously(); + if (tile.holdForFade()) { + // Since it was rendered in the last frame, we know we have it + // Don't mark the tile "Required" to avoid triggering a new network request + retainTileFn(tile, TileNecessity::Optional); + renderTiles.emplace_back(previouslyRenderedTile.first, tile); + rendered.emplace(previouslyRenderedTile.first); + } + } if (type != SourceType::Annotations) { size_t conservativeCacheSize = @@ -177,6 +198,13 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer auto tilesIt = tiles.begin(); auto retainIt = retain.begin(); while (tilesIt != tiles.end()) { + auto renderedIt = rendered.find(tilesIt->first.toUnwrapped()); + if (renderedIt == rendered.end()) { + // Since this tile isn't in the render set, crossTileIDs won't be kept + // updated by CrossTileSymbolIndex. We need to reset the stored crossTileIDs + // so they're not reused if/when this tile is re-added to the render set + tilesIt->second->resetCrossTileIDs(); + } if (retainIt == retain.end() || tilesIt->first < *retainIt) { if (!needsRelayout) { tilesIt->second->setNecessity(TileNecessity::Optional); @@ -193,20 +221,15 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer } for (auto& pair : tiles) { - const PlacementConfig config { parameters.transformState.getAngle(), - parameters.transformState.getPitch(), - parameters.transformState.getCameraToCenterDistance(), - parameters.transformState.getCameraToTileDistance(pair.first.toUnwrapped()), - parameters.debugOptions & MapDebugOptions::Collision }; - - pair.second->setPlacementConfig(config); + pair.second->setShowCollisionBoxes(parameters.debugOptions & MapDebugOptions::Collision); } } std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, const std::vector<const RenderLayer*>& layers, - const RenderedQueryOptions& options) const { + const RenderedQueryOptions& options, + const CollisionIndex& collisionIndex) const { std::unordered_map<std::string, std::vector<Feature>> result; if (renderTiles.empty() || geometry.empty()) { return result; @@ -249,7 +272,8 @@ std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRendered tileSpaceQueryGeometry, transformState, layers, - options); + options, + collisionIndex); } return result; diff --git a/src/mbgl/renderer/tile_pyramid.hpp b/src/mbgl/renderer/tile_pyramid.hpp index ac4572b103..feab8a838c 100644 --- a/src/mbgl/renderer/tile_pyramid.hpp +++ b/src/mbgl/renderer/tile_pyramid.hpp @@ -51,7 +51,8 @@ public: queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, const std::vector<const RenderLayer*>&, - const RenderedQueryOptions& options) const; + const RenderedQueryOptions& options, + const CollisionIndex& collisionIndex) const; std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const; |