summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Hay Kurtz <andrew.hay.kurtz@gmail.com>2019-10-29 13:49:22 -0700
committerMikhail Pozdnyakov <mikhail.pozdnyakov@mapbox.com>2020-04-14 22:30:40 +0300
commit0c95acf10379266e4142572b6cc7fb1c29271f3b (patch)
tree562c723da46b44a6c5905586f7a25f5194213d15
parent08ad74216442a8c306a3d7ca4696f5ddb780557f (diff)
downloadqtlocation-mapboxgl-0c95acf10379266e4142572b6cc7fb1c29271f3b.tar.gz
Enable 'circle-sort-key' layout property
-rw-r--r--CMakeLists.txt1
-rw-r--r--include/mbgl/layermanager/circle_layer_factory.hpp4
-rw-r--r--include/mbgl/style/layers/circle_layer.hpp6
-rw-r--r--metrics/expectations/platform-all/render-tests/circle-sort-key/literal/expected.pngbin0 -> 950 bytes
-rw-r--r--metrics/ignores/platform-all.json1
-rwxr-xr-xscripts/generate-style-code.js3
-rw-r--r--src/mbgl/layermanager/circle_layer_factory.cpp8
-rw-r--r--src/mbgl/layout/circle_layout.hpp165
-rw-r--r--src/mbgl/programs/program.hpp41
-rw-r--r--src/mbgl/renderer/buckets/circle_bucket.cpp74
-rw-r--r--src/mbgl/renderer/buckets/circle_bucket.hpp13
-rw-r--r--src/mbgl/renderer/layers/render_circle_layer.cpp82
-rw-r--r--src/mbgl/style/layers/circle_layer.cpp34
-rw-r--r--src/mbgl/style/layers/circle_layer_impl.cpp3
-rw-r--r--src/mbgl/style/layers/circle_layer_impl.hpp1
-rw-r--r--src/mbgl/style/layers/circle_layer_properties.hpp9
-rw-r--r--src/mbgl/style/layers/layer.cpp.ejs5
-rw-r--r--test/gl/bucket.test.cpp7
18 files changed, 353 insertions, 104 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c024d7f6cb..583c3df593 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -341,6 +341,7 @@ add_library(
${PROJECT_SOURCE_DIR}/src/mbgl/layermanager/line_layer_factory.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/layermanager/raster_layer_factory.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/layermanager/symbol_layer_factory.cpp
+ ${PROJECT_SOURCE_DIR}/src/mbgl/layout/circle_layout.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/layout/clip_lines.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/layout/clip_lines.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/layout/layout.hpp
diff --git a/include/mbgl/layermanager/circle_layer_factory.hpp b/include/mbgl/layermanager/circle_layer_factory.hpp
index 51135d3383..aaf5fddfb6 100644
--- a/include/mbgl/layermanager/circle_layer_factory.hpp
+++ b/include/mbgl/layermanager/circle_layer_factory.hpp
@@ -8,7 +8,9 @@ class CircleLayerFactory : public LayerFactory {
protected:
const style::LayerTypeInfo* getTypeInfo() const noexcept final;
std::unique_ptr<style::Layer> createLayer(const std::string& id, const style::conversion::Convertible& value) noexcept final;
- std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<Immutable<style::LayerProperties>>&) noexcept final;
+ std::unique_ptr<Layout> createLayout(const LayoutParameters& parameters,
+ std::unique_ptr<GeometryTileLayer> tileLayer,
+ const std::vector<Immutable<style::LayerProperties>>& group) noexcept final;
std::unique_ptr<RenderLayer> createRenderLayer(Immutable<style::Layer::Impl>) noexcept final;
};
diff --git a/include/mbgl/style/layers/circle_layer.hpp b/include/mbgl/style/layers/circle_layer.hpp
index f0e9787caa..aac02121e1 100644
--- a/include/mbgl/style/layers/circle_layer.hpp
+++ b/include/mbgl/style/layers/circle_layer.hpp
@@ -19,6 +19,12 @@ public:
CircleLayer(const std::string& layerID, const std::string& sourceID);
~CircleLayer() final;
+ // Layout properties
+
+ static PropertyValue<float> getDefaultCircleSortKey();
+ const PropertyValue<float>& getCircleSortKey() const;
+ void setCircleSortKey(const PropertyValue<float>&);
+
// Paint properties
static PropertyValue<float> getDefaultCircleBlur();
diff --git a/metrics/expectations/platform-all/render-tests/circle-sort-key/literal/expected.png b/metrics/expectations/platform-all/render-tests/circle-sort-key/literal/expected.png
new file mode 100644
index 0000000000..78c42d43f0
--- /dev/null
+++ b/metrics/expectations/platform-all/render-tests/circle-sort-key/literal/expected.png
Binary files differ
diff --git a/metrics/ignores/platform-all.json b/metrics/ignores/platform-all.json
index 9e20b2ffc5..da53a7a559 100644
--- a/metrics/ignores/platform-all.json
+++ b/metrics/ignores/platform-all.json
@@ -55,7 +55,6 @@
"render-tests/background-color/transition": "https://github.com/mapbox/mapbox-gl-native/issues/10619",
"render-tests/canvas/default": "skip - js specific",
"render-tests/canvas/update": "skip - js specific",
- "render-tests/circle-sort-key/literal": "https://github.com/mapbox/mapbox-gl-native/issues/15008",
"render-tests/collator/default": "Some test platforms don't resolve 'en' locale",
"render-tests/collator/resolved-locale": "Some test platforms don't resolve 'en' locale",
"render-tests/custom-layer-js/depth": "skip - js specific",
diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js
index c9191d59e1..de70fdcbe8 100755
--- a/scripts/generate-style-code.js
+++ b/scripts/generate-style-code.js
@@ -6,9 +6,6 @@ const ejs = require('ejs');
const spec = require('./style-spec');
const colorParser = require('csscolorparser');
-// FIXME: https://github.com/mapbox/mapbox-gl-native/issues/15008
-delete spec.layout_circle["circle-sort-key"]
-
require('./style-code');
function parseCSSColor(str) {
diff --git a/src/mbgl/layermanager/circle_layer_factory.cpp b/src/mbgl/layermanager/circle_layer_factory.cpp
index ce28270c0b..5bde1ede8b 100644
--- a/src/mbgl/layermanager/circle_layer_factory.cpp
+++ b/src/mbgl/layermanager/circle_layer_factory.cpp
@@ -1,5 +1,6 @@
#include <mbgl/layermanager/circle_layer_factory.hpp>
+#include <mbgl/layout/circle_layout.hpp>
#include <mbgl/renderer/buckets/circle_bucket.hpp>
#include <mbgl/renderer/layers/render_circle_layer.hpp>
#include <mbgl/style/layers/circle_layer.hpp>
@@ -20,8 +21,11 @@ std::unique_ptr<style::Layer> CircleLayerFactory::createLayer(const std::string&
return std::unique_ptr<style::Layer>(new style::CircleLayer(id, *source));
}
-std::unique_ptr<Bucket> CircleLayerFactory::createBucket(const BucketParameters& parameters, const std::vector<Immutable<style::LayerProperties>>& layers) noexcept {
- return std::make_unique<CircleBucket>(parameters, layers);
+std::unique_ptr<Layout> CircleLayerFactory::createLayout(
+ const LayoutParameters& parameters,
+ std::unique_ptr<GeometryTileLayer> layer,
+ const std::vector<Immutable<style::LayerProperties>>& group) noexcept {
+ return std::make_unique<CircleLayout>(parameters.bucketParameters, group, std::move(layer));
}
std::unique_ptr<RenderLayer> CircleLayerFactory::createRenderLayer(Immutable<style::Layer::Impl> impl) noexcept {
diff --git a/src/mbgl/layout/circle_layout.hpp b/src/mbgl/layout/circle_layout.hpp
new file mode 100644
index 0000000000..0f4f1d0328
--- /dev/null
+++ b/src/mbgl/layout/circle_layout.hpp
@@ -0,0 +1,165 @@
+#pragma once
+#include <mbgl/geometry/feature_index.hpp>
+#include <mbgl/layout/layout.hpp>
+#include <mbgl/renderer/bucket_parameters.hpp>
+#include <mbgl/renderer/buckets/circle_bucket.hpp>
+#include <mbgl/renderer/render_layer.hpp>
+#include <mbgl/style/layers/circle_layer_impl.hpp>
+
+namespace mbgl {
+
+class CircleFeature {
+public:
+ friend bool operator<(const CircleFeature& lhs, const CircleFeature& rhs) { return lhs.sortKey < rhs.sortKey; }
+
+ size_t i;
+ std::unique_ptr<GeometryTileFeature> feature;
+ float sortKey;
+};
+
+class CircleLayout : public Layout {
+public:
+ CircleLayout(const BucketParameters& parameters,
+ const std::vector<Immutable<style::LayerProperties>>& group,
+ std::unique_ptr<GeometryTileLayer> sourceLayer_)
+ : sourceLayer(std::move(sourceLayer_)),
+ zoom(parameters.tileID.overscaledZ),
+ mode(parameters.mode),
+ hasPattern(false) {
+ assert(!group.empty());
+ auto leaderLayerProperties = staticImmutableCast<style::CircleLayerProperties>(group.front());
+ unevaluatedLayout = leaderLayerProperties->layerImpl().layout;
+ layout = unevaluatedLayout.evaluate(PropertyEvaluationParameters(zoom));
+ sourceLayerID = leaderLayerProperties->layerImpl().sourceLayer;
+ bucketLeaderID = leaderLayerProperties->layerImpl().id;
+
+ for (const auto& layerProperties : group) {
+ const std::string& layerId = layerProperties->baseImpl->id;
+ layerPropertiesMap.emplace(layerId, layerProperties);
+ }
+
+ const size_t featureCount = sourceLayer->featureCount();
+ for (size_t i = 0; i < featureCount; ++i) {
+ auto feature = sourceLayer->getFeature(i);
+ if (!leaderLayerProperties->layerImpl().filter(
+ style::expression::EvaluationContext{this->zoom, feature.get()}))
+ continue;
+
+ auto sortKey = evaluateSortKey(*feature);
+
+ CircleFeature circleFeature{i, std::move(feature), sortKey};
+ const auto sortPosition = std::lower_bound(features.cbegin(), features.cend(), circleFeature);
+ features.insert(sortPosition, std::move(circleFeature));
+ }
+ };
+
+ ~CircleLayout() final = default;
+
+ bool hasDependencies() const override { return hasPattern; }
+
+ void createBucket(const ImagePositions&,
+ std::unique_ptr<FeatureIndex>& featureIndex,
+ std::unordered_map<std::string, LayerRenderData>& renderData,
+ const bool,
+ const bool,
+ const CanonicalTileID& canonical) override {
+ auto bucket = std::make_shared<CircleBucket>(layerPropertiesMap, mode, zoom);
+
+ for (auto& circleFeature : features) {
+ const auto i = circleFeature.i;
+ std::unique_ptr<GeometryTileFeature> feature = std::move(circleFeature.feature);
+ const GeometryCollection& geometries = feature->getGeometries();
+
+ addCircle(*bucket, *feature, geometries, i, circleFeature.sortKey, canonical);
+ featureIndex->insert(geometries, i, sourceLayerID, bucketLeaderID);
+ }
+ if (bucket->hasData()) {
+ for (const auto& pair : layerPropertiesMap) {
+ renderData.emplace(pair.first, LayerRenderData{bucket, pair.second});
+ }
+ }
+ };
+
+private:
+ void addCircle(CircleBucket& bucket,
+ const GeometryTileFeature& feature,
+ const GeometryCollection& geometry,
+ std::size_t featureIndex,
+ float sortKey,
+ const CanonicalTileID& canonical) {
+ constexpr const uint16_t vertexLength = 4;
+
+ auto& segments = bucket.segments;
+ auto& vertices = bucket.vertices;
+ auto& triangles = bucket.triangles;
+
+ for (auto& circle : geometry) {
+ for (auto& point : circle) {
+ auto x = point.x;
+ auto y = point.y;
+
+ // 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::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()) {
+ // Move to a new segments because the old one can't hold the geometry.
+ segments.emplace_back(vertices.elements(), triangles.elements(), 0ul, 0ul, sortKey);
+ }
+
+ // this geometry will be of the Point type, and we'll derive
+ // two triangles from it.
+ //
+ // ┌─────────┐
+ // │ 4 3 │
+ // │ │
+ // │ 1 2 │
+ // └─────────┘
+ //
+ vertices.emplace_back(CircleProgram::vertex(point, -1, -1)); // 1
+ vertices.emplace_back(CircleProgram::vertex(point, 1, -1)); // 2
+ vertices.emplace_back(CircleProgram::vertex(point, 1, 1)); // 3
+ vertices.emplace_back(CircleProgram::vertex(point, -1, 1)); // 4
+
+ auto& segment = segments.back();
+ assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max());
+ uint16_t index = segment.vertexLength;
+
+ // 1, 2, 3
+ // 1, 4, 3
+ triangles.emplace_back(index, index + 1, index + 2);
+ triangles.emplace_back(index, index + 3, index + 2);
+
+ segment.vertexLength += vertexLength;
+ segment.indexLength += 6;
+ }
+ }
+
+ for (auto& pair : bucket.paintPropertyBinders) {
+ pair.second.populateVertexVectors(feature, vertices.elements(), featureIndex, {}, {}, canonical);
+ }
+ }
+
+ float evaluateSortKey(const GeometryTileFeature& sourceFeature) {
+ const auto sortKeyProperty = layout.template get<style::CircleSortKey>();
+ return sortKeyProperty.evaluate(sourceFeature, zoom, style::CircleSortKey::defaultValue());
+ }
+
+ std::map<std::string, Immutable<style::LayerProperties>> layerPropertiesMap;
+ std::string bucketLeaderID;
+
+ const std::unique_ptr<GeometryTileLayer> sourceLayer;
+ std::list<CircleFeature> features;
+ typename style::CircleLayoutProperties::Unevaluated unevaluatedLayout;
+ typename style::CircleLayoutProperties::PossiblyEvaluated layout;
+
+ const float zoom;
+ const MapMode mode;
+ std::string sourceLayerID;
+ bool hasPattern;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/programs/program.hpp b/src/mbgl/programs/program.hpp
index ae9d1d3669..9f833a774d 100644
--- a/src/mbgl/programs/program.hpp
+++ b/src/mbgl/programs/program.hpp
@@ -79,6 +79,47 @@ public:
const gfx::ColorMode& colorMode,
const gfx::CullFaceMode& cullFaceMode,
const gfx::IndexBuffer& indexBuffer,
+ const Segment<AttributeList>& segment,
+ const UniformValues& uniformValues,
+ const AttributeBindings& allAttributeBindings,
+ const TextureBindings& textureBindings,
+ const std::string& layerID) {
+ static_assert(Primitive == gfx::PrimitiveTypeOf<DrawMode>::value, "incompatible draw mode");
+
+ if (!program) {
+ return;
+ }
+
+ auto drawScopeIt = segment.drawScopes.find(layerID);
+ if (drawScopeIt == segment.drawScopes.end()) {
+ drawScopeIt = segment.drawScopes.emplace(layerID, context.createDrawScope()).first;
+ }
+
+ program->draw(context,
+ renderPass,
+ drawMode,
+ depthMode,
+ stencilMode,
+ colorMode,
+ cullFaceMode,
+ uniformValues,
+ drawScopeIt->second,
+ allAttributeBindings.offset(segment.vertexOffset),
+ textureBindings,
+ indexBuffer,
+ segment.indexOffset,
+ segment.indexLength);
+ }
+
+ template <class DrawMode>
+ void draw(gfx::Context& context,
+ gfx::RenderPass& renderPass,
+ const DrawMode& drawMode,
+ const gfx::DepthMode& depthMode,
+ const gfx::StencilMode& stencilMode,
+ const gfx::ColorMode& colorMode,
+ const gfx::CullFaceMode& cullFaceMode,
+ const gfx::IndexBuffer& indexBuffer,
const SegmentVector<AttributeList>& segments,
const UniformValues& uniformValues,
const AttributeBindings& allAttributeBindings,
diff --git a/src/mbgl/renderer/buckets/circle_bucket.cpp b/src/mbgl/renderer/buckets/circle_bucket.cpp
index 744b559c42..5a1184f5fd 100644
--- a/src/mbgl/renderer/buckets/circle_bucket.cpp
+++ b/src/mbgl/renderer/buckets/circle_bucket.cpp
@@ -10,15 +10,14 @@ namespace mbgl {
using namespace style;
-CircleBucket::CircleBucket(const BucketParameters& parameters, const std::vector<Immutable<style::LayerProperties>>& layers)
- : mode(parameters.mode) {
- for (const auto& layer : layers) {
- paintPropertyBinders.emplace(
- std::piecewise_construct,
- std::forward_as_tuple(layer->baseImpl->id),
- std::forward_as_tuple(
- getEvaluated<CircleLayerProperties>(layer),
- parameters.tileID.overscaledZ));
+CircleBucket::CircleBucket(const std::map<std::string, Immutable<LayerProperties>>& layerPaintProperties,
+ const MapMode mode_,
+ const float zoom)
+ : mode(mode_) {
+ for (const auto& pair : layerPaintProperties) {
+ paintPropertyBinders.emplace(std::piecewise_construct,
+ std::forward_as_tuple(pair.first),
+ std::forward_as_tuple(getEvaluated<CircleLayerProperties>(pair.second), zoom));
}
}
@@ -41,63 +40,6 @@ bool CircleBucket::hasData() const {
return !segments.empty();
}
-void CircleBucket::addFeature(const GeometryTileFeature& feature,
- const GeometryCollection& geometry,
- const ImagePositions&,
- const PatternLayerMap&,
- std::size_t featureIndex,
- const CanonicalTileID& canonical) {
- constexpr const uint16_t vertexLength = 4;
-
- for (auto& circle : geometry) {
- for(auto& point : circle) {
- auto x = point.x;
- auto y = point.y;
-
- // 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::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()) {
- // Move to a new segments because the old one can't hold the geometry.
- segments.emplace_back(vertices.elements(), triangles.elements());
- }
-
- // this geometry will be of the Point type, and we'll derive
- // two triangles from it.
- //
- // ┌─────────┐
- // │ 4 3 │
- // │ │
- // │ 1 2 │
- // └─────────┘
- //
- vertices.emplace_back(CircleProgram::vertex(point, -1, -1)); // 1
- vertices.emplace_back(CircleProgram::vertex(point, 1, -1)); // 2
- vertices.emplace_back(CircleProgram::vertex(point, 1, 1)); // 3
- vertices.emplace_back(CircleProgram::vertex(point, -1, 1)); // 4
-
- auto& segment = segments.back();
- assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max());
- uint16_t index = segment.vertexLength;
-
- // 1, 2, 3
- // 1, 4, 3
- triangles.emplace_back(index, index + 1, index + 2);
- triangles.emplace_back(index, index + 3, index + 2);
-
- segment.vertexLength += vertexLength;
- segment.indexLength += 6;
- }
- }
-
- for (auto& pair : paintPropertyBinders) {
- pair.second.populateVertexVectors(feature, vertices.elements(), featureIndex, {}, {}, canonical);
- }
-}
-
template <class Property>
static float get(const CirclePaintProperties::PossiblyEvaluated& evaluated, const std::string& id, const std::map<std::string, CircleProgram::Binders>& paintPropertyBinders) {
auto it = paintPropertyBinders.find(id);
diff --git a/src/mbgl/renderer/buckets/circle_bucket.hpp b/src/mbgl/renderer/buckets/circle_bucket.hpp
index 17ddd9dc10..221deb5f17 100644
--- a/src/mbgl/renderer/buckets/circle_bucket.hpp
+++ b/src/mbgl/renderer/buckets/circle_bucket.hpp
@@ -15,15 +15,12 @@ class BucketParameters;
class CircleBucket final : public Bucket {
public:
- CircleBucket(const BucketParameters&, const std::vector<Immutable<style::LayerProperties>>&);
- ~CircleBucket() override;
+ using PossiblyEvaluatedLayoutProperties = style::CircleLayoutProperties::PossiblyEvaluated;
- void addFeature(const GeometryTileFeature&,
- const GeometryCollection&,
- const ImagePositions&,
- const PatternLayerMap&,
- std::size_t,
- const CanonicalTileID&) override;
+ CircleBucket(const std::map<std::string, Immutable<style::LayerProperties>>& layerPaintProperties,
+ const MapMode mode,
+ const float zoom);
+ ~CircleBucket() override;
bool hasData() const override;
diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp
index a8a70d2a3a..a85b82b2d2 100644
--- a/src/mbgl/renderer/layers/render_circle_layer.cpp
+++ b/src/mbgl/renderer/layers/render_circle_layer.cpp
@@ -17,6 +17,32 @@ using namespace style;
namespace {
+struct RenderableSegment {
+ RenderableSegment(const Segment<CircleAttributes>& segment_,
+ CircleProgram& programInstance_,
+ const CircleBucket& bucket_,
+ const CircleProgram::UniformValues& allUniformValues_,
+ const CircleProgram::AttributeBindings& allAttributeBindings_,
+ float sortKey_)
+ : segment(segment_),
+ programInstance(programInstance_),
+ bucket(bucket_),
+ allUniformValues(allUniformValues_),
+ allAttributeBindings(allAttributeBindings_),
+ sortKey(sortKey_) {}
+
+ const Segment<CircleAttributes>& segment;
+ CircleProgram& programInstance;
+ const CircleBucket& bucket;
+ const CircleProgram::UniformValues& allUniformValues;
+ const CircleProgram::AttributeBindings& allAttributeBindings;
+ const float sortKey;
+
+ friend bool operator<(const RenderableSegment& lhs, const RenderableSegment& rhs) {
+ return lhs.sortKey < rhs.sortKey;
+ }
+};
+
inline const style::CircleLayer::Impl& impl_cast(const Immutable<style::Layer::Impl>& impl) {
assert(impl->getTypeInfo() == CircleLayer::Impl::staticTypeInfo());
return static_cast<const style::CircleLayer::Impl&>(*impl);
@@ -63,6 +89,9 @@ void RenderCircleLayer::render(PaintParameters& parameters) {
return;
}
+ const bool sortFeaturesByKey = !impl_cast(baseImpl).layout.get<CircleSortKey>().isUndefined();
+ std::multiset<RenderableSegment> renderableSegments{};
+
for (const RenderTile& tile : *renderTiles) {
const LayerRenderData* renderData = getRenderDataForPass(tile, parameters.pass);
if (!renderData) {
@@ -96,21 +125,44 @@ void RenderCircleLayer::render(PaintParameters& parameters) {
checkRenderability(parameters, CircleProgram::activeBindingCount(allAttributeBindings));
- programInstance.draw(
- parameters.context,
- *parameters.renderPass,
- gfx::Triangles(),
- parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly),
- gfx::StencilMode::disabled(),
- parameters.colorModeForRenderPass(),
- gfx::CullFaceMode::disabled(),
- *bucket.indexBuffer,
- bucket.segments,
- allUniformValues,
- allAttributeBindings,
- CircleProgram::TextureBindings{},
- getID()
- );
+ if (sortFeaturesByKey) {
+ for (auto& segment : bucket.segments) {
+ renderableSegments.emplace(
+ segment, programInstance, bucket, allUniformValues, allAttributeBindings, segment.sortKey);
+ }
+ } else {
+ programInstance.draw(parameters.context,
+ *parameters.renderPass,
+ gfx::Triangles(),
+ parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly),
+ gfx::StencilMode::disabled(),
+ parameters.colorModeForRenderPass(),
+ gfx::CullFaceMode::disabled(),
+ *bucket.indexBuffer,
+ bucket.segments,
+ allUniformValues,
+ allAttributeBindings,
+ CircleProgram::TextureBindings{},
+ getID());
+ }
+ }
+
+ if (sortFeaturesByKey) {
+ for (const auto& renderable : renderableSegments) {
+ renderable.programInstance.draw(parameters.context,
+ *parameters.renderPass,
+ gfx::Triangles(),
+ parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly),
+ gfx::StencilMode::disabled(),
+ parameters.colorModeForRenderPass(),
+ gfx::CullFaceMode::disabled(),
+ *renderable.bucket.indexBuffer,
+ renderable.segment,
+ renderable.allUniformValues,
+ renderable.allAttributeBindings,
+ CircleProgram::TextureBindings{},
+ getID());
+ }
}
}
diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp
index ad34ba8223..bf415ea42d 100644
--- a/src/mbgl/style/layers/circle_layer.cpp
+++ b/src/mbgl/style/layers/circle_layer.cpp
@@ -24,7 +24,7 @@ const LayerTypeInfo* CircleLayer::Impl::staticTypeInfo() noexcept {
const static LayerTypeInfo typeInfo{"circle",
LayerTypeInfo::Source::Required,
LayerTypeInfo::Pass3D::NotRequired,
- LayerTypeInfo::Layout::NotRequired,
+ LayerTypeInfo::Layout::Required,
LayerTypeInfo::FadingTiles::NotRequired,
LayerTypeInfo::CrossTileIndex::NotRequired,
LayerTypeInfo::TileKind::Geometry};
@@ -57,11 +57,27 @@ std::unique_ptr<Layer> CircleLayer::cloneRef(const std::string& id_) const {
return std::make_unique<CircleLayer>(std::move(impl_));
}
-void CircleLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const {
+void CircleLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>& writer) const {
+ layout.stringify(writer);
}
// Layout properties
+PropertyValue<float> CircleLayer::getDefaultCircleSortKey() {
+ return CircleSortKey::defaultValue();
+}
+
+const PropertyValue<float>& CircleLayer::getCircleSortKey() const {
+ return impl().layout.get<CircleSortKey>();
+}
+
+void CircleLayer::setCircleSortKey(const PropertyValue<float>& value) {
+ if (value == getCircleSortKey()) return;
+ auto impl_ = mutableImpl();
+ impl_->layout.get<CircleSortKey>() = value;
+ baseImpl = std::move(impl_);
+ observer->onLayerChanged(*this);
+}
// Paint properties
@@ -391,6 +407,7 @@ enum class Property : uint8_t {
CircleStrokeWidthTransition,
CircleTranslateTransition,
CircleTranslateAnchorTransition,
+ CircleSortKey = kPaintPropertyCount,
};
template <typename T>
@@ -420,7 +437,8 @@ MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map<
{"circle-stroke-opacity-transition", toUint8(Property::CircleStrokeOpacityTransition)},
{"circle-stroke-width-transition", toUint8(Property::CircleStrokeWidthTransition)},
{"circle-translate-transition", toUint8(Property::CircleTranslateTransition)},
- {"circle-translate-anchor-transition", toUint8(Property::CircleTranslateAnchorTransition)}});
+ {"circle-translate-anchor-transition", toUint8(Property::CircleTranslateAnchorTransition)},
+ {"circle-sort-key", toUint8(Property::CircleSortKey)}});
StyleProperty getLayerProperty(const CircleLayer& layer, Property property) {
switch (property) {
@@ -468,6 +486,8 @@ StyleProperty getLayerProperty(const CircleLayer& layer, Property property) {
return makeStyleProperty(layer.getCircleTranslateTransition());
case Property::CircleTranslateAnchorTransition:
return makeStyleProperty(layer.getCircleTranslateAnchorTransition());
+ case Property::CircleSortKey:
+ return makeStyleProperty(layer.getCircleSortKey());
}
return {};
}
@@ -500,7 +520,8 @@ optional<Error> CircleLayer::setPropertyInternal(const std::string& name, const
auto property = static_cast<Property>(it->second);
if (property == Property::CircleBlur || property == Property::CircleOpacity || property == Property::CircleRadius ||
- property == Property::CircleStrokeOpacity || property == Property::CircleStrokeWidth) {
+ property == Property::CircleStrokeOpacity || property == Property::CircleStrokeWidth ||
+ property == Property::CircleSortKey) {
Error error;
const auto& typedValue = convert<PropertyValue<float>>(value, error, true, false);
if (!typedValue) {
@@ -531,6 +552,11 @@ optional<Error> CircleLayer::setPropertyInternal(const std::string& name, const
setCircleStrokeWidth(*typedValue);
return nullopt;
}
+
+ if (property == Property::CircleSortKey) {
+ setCircleSortKey(*typedValue);
+ return nullopt;
+ }
}
if (property == Property::CircleColor || property == Property::CircleStrokeColor) {
Error error;
diff --git a/src/mbgl/style/layers/circle_layer_impl.cpp b/src/mbgl/style/layers/circle_layer_impl.cpp
index bf0688ac8b..d40cc4bf9a 100644
--- a/src/mbgl/style/layers/circle_layer_impl.cpp
+++ b/src/mbgl/style/layers/circle_layer_impl.cpp
@@ -6,8 +6,7 @@ namespace style {
bool CircleLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const {
assert(other.getTypeInfo() == getTypeInfo());
const auto& impl = static_cast<const style::CircleLayer::Impl&>(other);
- return filter != impl.filter ||
- visibility != impl.visibility ||
+ return filter != impl.filter || visibility != impl.visibility || layout != impl.layout ||
paint.hasDataDrivenPropertyDifference(impl.paint);
}
diff --git a/src/mbgl/style/layers/circle_layer_impl.hpp b/src/mbgl/style/layers/circle_layer_impl.hpp
index 9b3ce48706..4826e58a63 100644
--- a/src/mbgl/style/layers/circle_layer_impl.hpp
+++ b/src/mbgl/style/layers/circle_layer_impl.hpp
@@ -14,6 +14,7 @@ public:
bool hasLayoutDifference(const Layer::Impl&) const override;
void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override;
+ CircleLayoutProperties::Unevaluated layout;
CirclePaintProperties::Transitionable paint;
DECLARE_LAYER_TYPE_INFO;
diff --git a/src/mbgl/style/layers/circle_layer_properties.hpp b/src/mbgl/style/layers/circle_layer_properties.hpp
index 5204421d0b..c8ec81eed5 100644
--- a/src/mbgl/style/layers/circle_layer_properties.hpp
+++ b/src/mbgl/style/layers/circle_layer_properties.hpp
@@ -16,6 +16,11 @@
namespace mbgl {
namespace style {
+struct CircleSortKey : DataDrivenLayoutProperty<float> {
+ static constexpr const char *name() { return "circle-sort-key"; }
+ static float defaultValue() { return 0; }
+};
+
struct CircleBlur : DataDrivenPaintProperty<float, attributes::blur, uniforms::blur> {
static float defaultValue() { return 0; }
};
@@ -60,6 +65,10 @@ struct CircleTranslateAnchor : PaintProperty<TranslateAnchorType> {
static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; }
};
+class CircleLayoutProperties : public Properties<
+ CircleSortKey
+> {};
+
class CirclePaintProperties : public Properties<
CircleBlur,
CircleColor,
diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs
index fd5bf619f7..8fd4b1fef0 100644
--- a/src/mbgl/style/layers/layer.cpp.ejs
+++ b/src/mbgl/style/layers/layer.cpp.ejs
@@ -73,7 +73,10 @@ layerCapabilities['symbol'] = defaults.require('Source')
.require('CrossTileIndex')
.set('TileKind', 'Geometry')
.finalize();
-layerCapabilities['circle'] = defaults.require('Source').set('TileKind', 'Geometry').finalize();
+layerCapabilities['circle'] = defaults.require('Source')
+ .require('Layout')
+ .set('TileKind', 'Geometry')
+ .finalize();
layerCapabilities['line'] = layerCapabilities['fill'];
layerCapabilities['heatmap'] = defaults.require('Source')
.require('Pass3D')
diff --git a/test/gl/bucket.test.cpp b/test/gl/bucket.test.cpp
index 9f780fcffa..fd8644bfbc 100644
--- a/test/gl/bucket.test.cpp
+++ b/test/gl/bucket.test.cpp
@@ -47,10 +47,11 @@ TEST(Buckets, CircleBucket) {
gfx::BackendScope scope { backend };
gl::Context context{ backend };
- CircleBucket bucket { { {0, 0, 0}, MapMode::Static, 1.0, nullptr }, {} };
+ CircleBucket bucket{{}, MapMode::Static, 1.0};
ASSERT_FALSE(bucket.hasData());
ASSERT_FALSE(bucket.needsUpload());
+ // CircleBucket::addFeature() is a no-op.
GeometryCollection point { { { 0, 0 } } };
bucket.addFeature(StubGeometryTileFeature{{}, FeatureType::Point, point, properties},
point,
@@ -58,6 +59,10 @@ TEST(Buckets, CircleBucket) {
PatternLayerMap(),
0,
CanonicalTileID(0, 0, 0));
+ ASSERT_FALSE(bucket.hasData());
+ ASSERT_FALSE(bucket.needsUpload());
+
+ bucket.segments.emplace_back(0, 0);
ASSERT_TRUE(bucket.hasData());
ASSERT_TRUE(bucket.needsUpload());