summaryrefslogtreecommitdiff
path: root/src/mbgl/renderer
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/renderer')
-rw-r--r--src/mbgl/renderer/backend_scope.cpp66
-rw-r--r--src/mbgl/renderer/bucket.hpp21
-rw-r--r--src/mbgl/renderer/bucket_parameters.hpp1
-rw-r--r--src/mbgl/renderer/buckets/circle_bucket.cpp (renamed from src/mbgl/renderer/circle_bucket.cpp)12
-rw-r--r--src/mbgl/renderer/buckets/circle_bucket.hpp (renamed from src/mbgl/renderer/circle_bucket.hpp)2
-rw-r--r--src/mbgl/renderer/buckets/debug_bucket.cpp (renamed from src/mbgl/renderer/debug_bucket.cpp)4
-rw-r--r--src/mbgl/renderer/buckets/debug_bucket.hpp (renamed from src/mbgl/renderer/debug_bucket.hpp)0
-rw-r--r--src/mbgl/renderer/buckets/fill_bucket.cpp (renamed from src/mbgl/renderer/fill_bucket.cpp)12
-rw-r--r--src/mbgl/renderer/buckets/fill_bucket.hpp (renamed from src/mbgl/renderer/fill_bucket.hpp)1
-rw-r--r--src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp (renamed from src/mbgl/renderer/fill_extrusion_bucket.cpp)12
-rw-r--r--src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp (renamed from src/mbgl/renderer/fill_extrusion_bucket.hpp)1
-rw-r--r--src/mbgl/renderer/buckets/line_bucket.cpp (renamed from src/mbgl/renderer/line_bucket.cpp)34
-rw-r--r--src/mbgl/renderer/buckets/line_bucket.hpp (renamed from src/mbgl/renderer/line_bucket.hpp)6
-rw-r--r--src/mbgl/renderer/buckets/raster_bucket.cpp110
-rw-r--r--src/mbgl/renderer/buckets/raster_bucket.hpp41
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.cpp (renamed from src/mbgl/renderer/symbol_bucket.cpp)23
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.hpp (renamed from src/mbgl/renderer/symbol_bucket.hpp)30
-rw-r--r--src/mbgl/renderer/cross_faded_property_evaluator.cpp5
-rw-r--r--src/mbgl/renderer/data_driven_property_evaluator.hpp10
-rw-r--r--src/mbgl/renderer/frame_history.cpp10
-rw-r--r--src/mbgl/renderer/frame_history.hpp1
-rw-r--r--src/mbgl/renderer/group_by_layout.cpp14
-rw-r--r--src/mbgl/renderer/image_atlas.cpp60
-rw-r--r--src/mbgl/renderer/image_atlas.hpp51
-rw-r--r--src/mbgl/renderer/image_manager.cpp184
-rw-r--r--src/mbgl/renderer/image_manager.hpp91
-rw-r--r--src/mbgl/renderer/layers/render_background_layer.cpp115
-rw-r--r--src/mbgl/renderer/layers/render_background_layer.hpp (renamed from src/mbgl/renderer/render_background_layer.hpp)16
-rw-r--r--src/mbgl/renderer/layers/render_circle_layer.cpp120
-rw-r--r--src/mbgl/renderer/layers/render_circle_layer.hpp (renamed from src/mbgl/renderer/render_circle_layer.hpp)16
-rw-r--r--src/mbgl/renderer/layers/render_custom_layer.cpp81
-rw-r--r--src/mbgl/renderer/layers/render_custom_layer.hpp (renamed from src/mbgl/renderer/render_custom_layer.hpp)24
-rw-r--r--src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp167
-rw-r--r--src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp (renamed from src/mbgl/renderer/render_fill_extrusion_layer.hpp)18
-rw-r--r--src/mbgl/renderer/layers/render_fill_layer.cpp205
-rw-r--r--src/mbgl/renderer/layers/render_fill_layer.hpp (renamed from src/mbgl/renderer/render_fill_layer.hpp)14
-rw-r--r--src/mbgl/renderer/layers/render_line_layer.cpp204
-rw-r--r--src/mbgl/renderer/layers/render_line_layer.hpp (renamed from src/mbgl/renderer/render_line_layer.hpp)27
-rw-r--r--src/mbgl/renderer/layers/render_raster_layer.cpp155
-rw-r--r--src/mbgl/renderer/layers/render_raster_layer.hpp (renamed from src/mbgl/renderer/render_raster_layer.hpp)15
-rw-r--r--src/mbgl/renderer/layers/render_symbol_layer.cpp325
-rw-r--r--src/mbgl/renderer/layers/render_symbol_layer.hpp (renamed from src/mbgl/renderer/render_symbol_layer.hpp)37
-rw-r--r--src/mbgl/renderer/paint_parameters.cpp98
-rw-r--r--src/mbgl/renderer/paint_parameters.hpp68
-rw-r--r--src/mbgl/renderer/paint_property_binder.hpp7
-rw-r--r--src/mbgl/renderer/painter.cpp430
-rw-r--r--src/mbgl/renderer/painter.hpp186
-rw-r--r--src/mbgl/renderer/painter_background.cpp84
-rw-r--r--src/mbgl/renderer/painter_circle.cpp58
-rw-r--r--src/mbgl/renderer/painter_clipping.cpp38
-rw-r--r--src/mbgl/renderer/painter_debug.cpp135
-rw-r--r--src/mbgl/renderer/painter_fill.cpp144
-rw-r--r--src/mbgl/renderer/painter_fill_extrusion.cpp89
-rw-r--r--src/mbgl/renderer/painter_line.cpp92
-rw-r--r--src/mbgl/renderer/painter_raster.cpp89
-rw-r--r--src/mbgl/renderer/painter_symbol.cpp166
-rw-r--r--src/mbgl/renderer/possibly_evaluated_property_value.hpp14
-rw-r--r--src/mbgl/renderer/property_evaluation_parameters.hpp10
-rw-r--r--src/mbgl/renderer/raster_bucket.cpp30
-rw-r--r--src/mbgl/renderer/raster_bucket.hpp22
-rw-r--r--src/mbgl/renderer/render_background_layer.cpp37
-rw-r--r--src/mbgl/renderer/render_circle_layer.cpp67
-rw-r--r--src/mbgl/renderer/render_custom_layer.cpp29
-rw-r--r--src/mbgl/renderer/render_fill_extrusion_layer.cpp55
-rw-r--r--src/mbgl/renderer/render_fill_layer.cpp71
-rw-r--r--src/mbgl/renderer/render_item.hpp36
-rw-r--r--src/mbgl/renderer/render_layer.cpp60
-rw-r--r--src/mbgl/renderer/render_layer.hpp30
-rw-r--r--src/mbgl/renderer/render_light.cpp20
-rw-r--r--src/mbgl/renderer/render_light.hpp85
-rw-r--r--src/mbgl/renderer/render_line_layer.cpp117
-rw-r--r--src/mbgl/renderer/render_pass.hpp8
-rw-r--r--src/mbgl/renderer/render_raster_layer.cpp35
-rw-r--r--src/mbgl/renderer/render_source.cpp36
-rw-r--r--src/mbgl/renderer/render_source.hpp59
-rw-r--r--src/mbgl/renderer/render_static_data.cpp67
-rw-r--r--src/mbgl/renderer/render_static_data.hpp39
-rw-r--r--src/mbgl/renderer/render_symbol_layer.cpp113
-rw-r--r--src/mbgl/renderer/render_tile.cpp129
-rw-r--r--src/mbgl/renderer/render_tile.hpp15
-rw-r--r--src/mbgl/renderer/renderer.cpp86
-rw-r--r--src/mbgl/renderer/renderer_backend.cpp69
-rw-r--r--src/mbgl/renderer/renderer_impl.cpp742
-rw-r--r--src/mbgl/renderer/renderer_impl.hpp111
-rw-r--r--src/mbgl/renderer/renderer_observer.hpp35
-rw-r--r--src/mbgl/renderer/sources/render_geojson_source.cpp96
-rw-r--r--src/mbgl/renderer/sources/render_geojson_source.hpp41
-rw-r--r--src/mbgl/renderer/sources/render_image_source.cpp214
-rw-r--r--src/mbgl/renderer/sources/render_image_source.hpp58
-rw-r--r--src/mbgl/renderer/sources/render_raster_source.cpp78
-rw-r--r--src/mbgl/renderer/sources/render_raster_source.hpp39
-rw-r--r--src/mbgl/renderer/sources/render_vector_source.cpp79
-rw-r--r--src/mbgl/renderer/sources/render_vector_source.hpp39
-rw-r--r--src/mbgl/renderer/style_diff.cpp79
-rw-r--r--src/mbgl/renderer/style_diff.hpp48
-rw-r--r--src/mbgl/renderer/tile_mask.hpp15
-rw-r--r--src/mbgl/renderer/tile_parameters.hpp33
-rw-r--r--src/mbgl/renderer/tile_pyramid.cpp173
-rw-r--r--src/mbgl/renderer/tile_pyramid.hpp42
-rw-r--r--src/mbgl/renderer/transition_parameters.hpp (renamed from src/mbgl/renderer/cascade_parameters.hpp)4
-rw-r--r--src/mbgl/renderer/transitioning_property.hpp75
-rw-r--r--src/mbgl/renderer/update_parameters.hpp33
102 files changed, 4517 insertions, 2881 deletions
diff --git a/src/mbgl/renderer/backend_scope.cpp b/src/mbgl/renderer/backend_scope.cpp
new file mode 100644
index 0000000000..fafeaabb39
--- /dev/null
+++ b/src/mbgl/renderer/backend_scope.cpp
@@ -0,0 +1,66 @@
+#include <mbgl/renderer/backend_scope.hpp>
+#include <mbgl/renderer/renderer_backend.hpp>
+#include <mbgl/util/thread_local.hpp>
+
+#include <cassert>
+
+namespace mbgl {
+
+static util::ThreadLocal<BackendScope> currentScope;
+
+BackendScope::BackendScope(RendererBackend& backend_, ScopeType scopeType_)
+ : priorScope(currentScope.get()),
+ nextScope(nullptr),
+ backend(backend_),
+ scopeType(scopeType_) {
+ if (priorScope) {
+ assert(priorScope->nextScope == nullptr);
+ priorScope->nextScope = this;
+ priorScope->deactivate();
+ }
+
+ activate();
+
+ currentScope.set(this);
+}
+
+BackendScope::~BackendScope() {
+ assert(nextScope == nullptr);
+ deactivate();
+
+ if (priorScope) {
+ priorScope->activate();
+ currentScope.set(priorScope);
+ assert(priorScope->nextScope == this);
+ priorScope->nextScope = nullptr;
+ } else {
+ currentScope.set(nullptr);
+ }
+}
+
+void BackendScope::activate() {
+ if (scopeType == ScopeType::Explicit &&
+ !(priorScope && this->backend == priorScope->backend) &&
+ !(nextScope && this->backend == nextScope->backend)) {
+ // Only activate when set to Explicit and
+ // only once per RenderBackend
+ backend.activate();
+ activated = true;
+ }
+}
+
+void BackendScope::deactivate() {
+ if (activated &&
+ !(nextScope && this->backend == nextScope->backend)) {
+ // Only deactivate when set to Explicit and
+ // only once per RenderBackend
+ backend.deactivate();
+ activated = false;
+ }
+}
+
+bool BackendScope::exists() {
+ return currentScope.get();
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/bucket.hpp b/src/mbgl/renderer/bucket.hpp
index 6c391cf014..9af511a03e 100644
--- a/src/mbgl/renderer/bucket.hpp
+++ b/src/mbgl/renderer/bucket.hpp
@@ -1,33 +1,26 @@
#pragma once
-#include <mbgl/renderer/render_pass.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
-#include <mbgl/renderer/render_layer.hpp>
#include <atomic>
-#include <string>
-#include <unordered_map>
namespace mbgl {
-class Painter;
-class PaintParameters;
-class RenderTile;
-
namespace gl {
class Context;
} // namespace gl
-namespace style {
-class Layer;
-} // namespace style
+class RenderLayer;
class Bucket : private util::noncopyable {
public:
Bucket() = default;
virtual ~Bucket() = default;
+ // Feature geometries are also used to populate the feature index.
+ // Obtaining these is a costly operation, so we do it only once, and
+ // pass-by-const-ref the geometries as a second parameter.
virtual void addFeature(const GeometryTileFeature&,
const GeometryCollection&) {};
@@ -35,10 +28,6 @@ public:
// this only happens once when the bucket is being rendered for the first time.
virtual void upload(gl::Context&) = 0;
- // Every time this bucket is getting rendered, this function is called. This happens either
- // once or twice (for Opaque and Transparent render passes).
- virtual void render(Painter&, PaintParameters&, const RenderLayer&, const RenderTile&) = 0;
-
virtual bool hasData() const = 0;
virtual float getQueryRadius(const RenderLayer&) const {
@@ -46,7 +35,7 @@ public:
};
bool needsUpload() const {
- return !uploaded;
+ return hasData() && !uploaded;
}
protected:
diff --git a/src/mbgl/renderer/bucket_parameters.hpp b/src/mbgl/renderer/bucket_parameters.hpp
index 1774ba2bbe..50ec4cf521 100644
--- a/src/mbgl/renderer/bucket_parameters.hpp
+++ b/src/mbgl/renderer/bucket_parameters.hpp
@@ -9,6 +9,7 @@ class BucketParameters {
public:
const OverscaledTileID tileID;
const MapMode mode;
+ const float pixelRatio;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/circle_bucket.cpp b/src/mbgl/renderer/buckets/circle_bucket.cpp
index 1e08eca478..04126990b3 100644
--- a/src/mbgl/renderer/circle_bucket.cpp
+++ b/src/mbgl/renderer/buckets/circle_bucket.cpp
@@ -1,9 +1,8 @@
-#include <mbgl/renderer/circle_bucket.hpp>
+#include <mbgl/renderer/buckets/circle_bucket.hpp>
#include <mbgl/renderer/bucket_parameters.hpp>
-#include <mbgl/renderer/painter.hpp>
#include <mbgl/programs/circle_program.hpp>
#include <mbgl/style/layers/circle_layer_impl.hpp>
-#include <mbgl/renderer/render_circle_layer.hpp>
+#include <mbgl/renderer/layers/render_circle_layer.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/math.hpp>
@@ -34,13 +33,6 @@ void CircleBucket::upload(gl::Context& context) {
uploaded = true;
}
-void CircleBucket::render(Painter& painter,
- PaintParameters& parameters,
- const RenderLayer& layer,
- const RenderTile& tile) {
- painter.renderCircle(parameters, *this, *layer.as<RenderCircleLayer>(), tile);
-}
-
bool CircleBucket::hasData() const {
return !segments.empty();
}
diff --git a/src/mbgl/renderer/circle_bucket.hpp b/src/mbgl/renderer/buckets/circle_bucket.hpp
index 0f27e2a7e3..78b6351bcb 100644
--- a/src/mbgl/renderer/circle_bucket.hpp
+++ b/src/mbgl/renderer/buckets/circle_bucket.hpp
@@ -23,8 +23,6 @@ public:
void upload(gl::Context&) override;
- void render(Painter&, PaintParameters&, const RenderLayer&, const RenderTile&) override;
-
float getQueryRadius(const RenderLayer&) const override;
gl::VertexVector<CircleLayoutVertex> vertices;
diff --git a/src/mbgl/renderer/debug_bucket.cpp b/src/mbgl/renderer/buckets/debug_bucket.cpp
index 2a514989cf..53c751c443 100644
--- a/src/mbgl/renderer/debug_bucket.cpp
+++ b/src/mbgl/renderer/buckets/debug_bucket.cpp
@@ -1,7 +1,7 @@
-#include <mbgl/renderer/debug_bucket.hpp>
-#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/buckets/debug_bucket.hpp>
#include <mbgl/programs/fill_program.hpp>
#include <mbgl/geometry/debug_font_data.hpp>
+#include <mbgl/tile/tile_id.hpp>
#include <mbgl/util/string.hpp>
#include <cmath>
diff --git a/src/mbgl/renderer/debug_bucket.hpp b/src/mbgl/renderer/buckets/debug_bucket.hpp
index fc3128e944..fc3128e944 100644
--- a/src/mbgl/renderer/debug_bucket.hpp
+++ b/src/mbgl/renderer/buckets/debug_bucket.hpp
diff --git a/src/mbgl/renderer/fill_bucket.cpp b/src/mbgl/renderer/buckets/fill_bucket.cpp
index 2409fd365b..110db887a1 100644
--- a/src/mbgl/renderer/fill_bucket.cpp
+++ b/src/mbgl/renderer/buckets/fill_bucket.cpp
@@ -1,9 +1,8 @@
-#include <mbgl/renderer/fill_bucket.hpp>
-#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/buckets/fill_bucket.hpp>
#include <mbgl/programs/fill_program.hpp>
#include <mbgl/renderer/bucket_parameters.hpp>
#include <mbgl/style/layers/fill_layer_impl.hpp>
-#include <mbgl/renderer/render_fill_layer.hpp>
+#include <mbgl/renderer/layers/render_fill_layer.hpp>
#include <mbgl/util/math.hpp>
#include <mapbox/earcut.hpp>
@@ -121,13 +120,6 @@ void FillBucket::upload(gl::Context& context) {
uploaded = true;
}
-void FillBucket::render(Painter& painter,
- PaintParameters& parameters,
- const RenderLayer& layer,
- const RenderTile& tile) {
- painter.renderFill(parameters, *this, *layer.as<RenderFillLayer>(), tile);
-}
-
bool FillBucket::hasData() const {
return !triangleSegments.empty() || !lineSegments.empty();
}
diff --git a/src/mbgl/renderer/fill_bucket.hpp b/src/mbgl/renderer/buckets/fill_bucket.hpp
index d3cd92d451..a50e1971f5 100644
--- a/src/mbgl/renderer/fill_bucket.hpp
+++ b/src/mbgl/renderer/buckets/fill_bucket.hpp
@@ -23,7 +23,6 @@ public:
bool hasData() const override;
void upload(gl::Context&) override;
- void render(Painter&, PaintParameters&, const RenderLayer&, const RenderTile&) override;
float getQueryRadius(const RenderLayer&) const override;
diff --git a/src/mbgl/renderer/fill_extrusion_bucket.cpp b/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp
index 2b352ab66a..7f53326fe1 100644
--- a/src/mbgl/renderer/fill_extrusion_bucket.cpp
+++ b/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp
@@ -1,9 +1,8 @@
-#include <mbgl/renderer/fill_extrusion_bucket.hpp>
-#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/buckets/fill_extrusion_bucket.hpp>
#include <mbgl/programs/fill_extrusion_program.hpp>
#include <mbgl/renderer/bucket_parameters.hpp>
#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp>
-#include <mbgl/renderer/render_fill_extrusion_layer.hpp>
+#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/constants.hpp>
@@ -154,13 +153,6 @@ void FillExtrusionBucket::upload(gl::Context& context) {
uploaded = true;
}
-void FillExtrusionBucket::render(Painter& painter,
- PaintParameters& parameters,
- const RenderLayer& layer,
- const RenderTile& tile) {
- painter.renderFillExtrusion(parameters, *this, *layer.as<RenderFillExtrusionLayer>(), tile);
-}
-
bool FillExtrusionBucket::hasData() const {
return !triangleSegments.empty();
}
diff --git a/src/mbgl/renderer/fill_extrusion_bucket.hpp b/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp
index d1e695c5a3..d57265ab16 100644
--- a/src/mbgl/renderer/fill_extrusion_bucket.hpp
+++ b/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp
@@ -21,7 +21,6 @@ public:
bool hasData() const override;
void upload(gl::Context&) override;
- void render(Painter&, PaintParameters&, const RenderLayer&, const RenderTile&) override;
float getQueryRadius(const RenderLayer&) const override;
diff --git a/src/mbgl/renderer/line_bucket.cpp b/src/mbgl/renderer/buckets/line_bucket.cpp
index c80b8900ea..a96518df38 100644
--- a/src/mbgl/renderer/line_bucket.cpp
+++ b/src/mbgl/renderer/buckets/line_bucket.cpp
@@ -1,6 +1,5 @@
-#include <mbgl/renderer/line_bucket.hpp>
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/renderer/render_line_layer.hpp>
+#include <mbgl/renderer/buckets/line_bucket.hpp>
+#include <mbgl/renderer/layers/render_line_layer.hpp>
#include <mbgl/renderer/bucket_parameters.hpp>
#include <mbgl/style/layers/line_layer_impl.hpp>
#include <mbgl/util/math.hpp>
@@ -14,9 +13,10 @@ using namespace style;
LineBucket::LineBucket(const BucketParameters& parameters,
const std::vector<const RenderLayer*>& layers,
- const style::LineLayoutProperties& layout_)
+ const style::LineLayoutProperties::Unevaluated& layout_)
: layout(layout_.evaluate(PropertyEvaluationParameters(parameters.tileID.overscaledZ))),
- overscaling(parameters.tileID.overscaleFactor()) {
+ overscaling(parameters.tileID.overscaleFactor()),
+ zoom(parameters.tileID.overscaledZ) {
for (const auto& layer : layers) {
paintPropertyBinders.emplace(
std::piecewise_construct,
@@ -30,7 +30,7 @@ LineBucket::LineBucket(const BucketParameters& parameters,
void LineBucket::addFeature(const GeometryTileFeature& feature,
const GeometryCollection& geometryCollection) {
for (auto& line : geometryCollection) {
- addGeometry(line, feature.getType());
+ addGeometry(line, feature);
}
for (auto& pair : paintPropertyBinders) {
@@ -63,7 +63,8 @@ const float LINE_DISTANCE_SCALE = 1.0 / 2.0;
// The maximum line distance, in tile units, that fits in the buffer.
const float MAX_LINE_DISTANCE = std::pow(2, LINE_DISTANCE_BUFFER_BITS) / LINE_DISTANCE_SCALE;
-void LineBucket::addGeometry(const GeometryCoordinates& coordinates, FeatureType type) {
+void LineBucket::addGeometry(const GeometryCoordinates& coordinates, const GeometryTileFeature& feature) {
+ const FeatureType type = feature.getType();
const std::size_t len = [&coordinates] {
std::size_t l = coordinates.size();
// If the line has duplicate vertices at the end, adjust length to remove them.
@@ -87,7 +88,9 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates, FeatureType
return;
}
- const float miterLimit = layout.get<LineJoin>() == LineJoinType::Bevel ? 1.05f : float(layout.get<LineMiterLimit>());
+ const LineJoinType joinType = layout.evaluate<LineJoin>(zoom, feature);
+
+ const float miterLimit = joinType == LineJoinType::Bevel ? 1.05f : float(layout.get<LineMiterLimit>());
const double sharpCornerOffset = SHARP_CORNER_OFFSET * (float(util::EXTENT) / (util::tileSize * overscaling));
@@ -183,7 +186,7 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates, FeatureType
const bool isSharpCorner = cosHalfAngle < COS_HALF_SHARP_CORNER && prevCoordinate && nextCoordinate;
if (isSharpCorner && i > first) {
- const double prevSegmentLength = util::dist<double>(*currentCoordinate, *prevCoordinate);
+ const auto prevSegmentLength = util::dist<double>(*currentCoordinate, *prevCoordinate);
if (prevSegmentLength > 2.0 * sharpCornerOffset) {
GeometryCoordinate newPrevVertex = *currentCoordinate - convertPoint<int16_t>(util::round(convertPoint<double>(*currentCoordinate - *prevCoordinate) * (sharpCornerOffset / prevSegmentLength)));
distance += util::dist<double>(newPrevVertex, *prevCoordinate);
@@ -194,7 +197,7 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates, FeatureType
// The join if a middle vertex, otherwise the cap
const bool middleVertex = prevCoordinate && nextCoordinate;
- LineJoinType currentJoin = layout.get<LineJoin>();
+ LineJoinType currentJoin = joinType;
const LineCapType currentCap = nextCoordinate ? beginCap : endCap;
if (middleVertex) {
@@ -356,7 +359,7 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates, FeatureType
}
if (isSharpCorner && i < len - 1) {
- const double nextSegmentLength = util::dist<double>(*currentCoordinate, *nextCoordinate);
+ const auto nextSegmentLength = util::dist<double>(*currentCoordinate, *nextCoordinate);
if (nextSegmentLength > 2 * sharpCornerOffset) {
GeometryCoordinate newCurrentVertex = *currentCoordinate + convertPoint<int16_t>(util::round(convertPoint<double>(*nextCoordinate - *currentCoordinate) * (sharpCornerOffset / nextSegmentLength)));
distance += util::dist<double>(newCurrentVertex, *currentCoordinate);
@@ -458,13 +461,6 @@ void LineBucket::upload(gl::Context& context) {
uploaded = true;
}
-void LineBucket::render(Painter& painter,
- PaintParameters& parameters,
- const RenderLayer& layer,
- const RenderTile& tile) {
- painter.renderLine(parameters, *this, *layer.as<RenderLineLayer>(), tile);
-}
-
bool LineBucket::hasData() const {
return !segments.empty();
}
@@ -480,7 +476,7 @@ static float get(const RenderLineLayer& layer, const std::map<std::string, LineP
}
float LineBucket::getLineWidth(const RenderLineLayer& layer) const {
- float lineWidth = layer.evaluated.get<LineWidth>();
+ float lineWidth = get<LineWidth>(layer, paintPropertyBinders);
float gapWidth = get<LineGapWidth>(layer, paintPropertyBinders);
if (gapWidth) {
diff --git a/src/mbgl/renderer/line_bucket.hpp b/src/mbgl/renderer/buckets/line_bucket.hpp
index 95ef2f9a6f..4fb77c377e 100644
--- a/src/mbgl/renderer/line_bucket.hpp
+++ b/src/mbgl/renderer/buckets/line_bucket.hpp
@@ -19,14 +19,13 @@ class LineBucket : public Bucket {
public:
LineBucket(const BucketParameters&,
const std::vector<const RenderLayer*>&,
- const style::LineLayoutProperties&);
+ const style::LineLayoutProperties::Unevaluated&);
void addFeature(const GeometryTileFeature&,
const GeometryCollection&) override;
bool hasData() const override;
void upload(gl::Context&) override;
- void render(Painter&, PaintParameters&, const RenderLayer&, const RenderTile&) override;
float getQueryRadius(const RenderLayer&) const override;
@@ -42,7 +41,7 @@ public:
std::map<std::string, LineProgram::PaintPropertyBinders> paintPropertyBinders;
private:
- void addGeometry(const GeometryCoordinates&, FeatureType);
+ void addGeometry(const GeometryCoordinates&, const GeometryTileFeature&);
struct TriangleElement {
TriangleElement(uint16_t a_, uint16_t b_, uint16_t c_) : a(a_), b(b_), c(c_) {}
@@ -60,6 +59,7 @@ private:
std::ptrdiff_t e3;
const uint32_t overscaling;
+ const float zoom;
float getLineWidth(const RenderLineLayer& layer) const;
};
diff --git a/src/mbgl/renderer/buckets/raster_bucket.cpp b/src/mbgl/renderer/buckets/raster_bucket.cpp
new file mode 100644
index 0000000000..a66dd42d74
--- /dev/null
+++ b/src/mbgl/renderer/buckets/raster_bucket.cpp
@@ -0,0 +1,110 @@
+#include <mbgl/renderer/buckets/raster_bucket.hpp>
+#include <mbgl/renderer/layers/render_raster_layer.hpp>
+#include <mbgl/programs/raster_program.hpp>
+#include <mbgl/gl/context.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+RasterBucket::RasterBucket(PremultipliedImage&& image_) {
+ image = std::make_shared<PremultipliedImage>(std::move(image_));
+}
+
+RasterBucket::RasterBucket(std::shared_ptr<PremultipliedImage> image_): image(image_) {
+
+}
+
+void RasterBucket::upload(gl::Context& context) {
+ if (!hasData()) {
+ return;
+ }
+ if (!texture) {
+ texture = context.createTexture(*image);
+ }
+ if (!segments.empty()) {
+ vertexBuffer = context.createVertexBuffer(std::move(vertices));
+ indexBuffer = context.createIndexBuffer(std::move(indices));
+ }
+ uploaded = true;
+}
+
+void RasterBucket::clear() {
+ vertexBuffer = {};
+ indexBuffer = {};
+ segments.clear();
+ vertices.clear();
+ indices.clear();
+
+ uploaded = false;
+}
+
+void RasterBucket::setImage(std::shared_ptr<PremultipliedImage> image_) {
+ image = std::move(image_);
+ texture = {};
+ 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 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) };
+
+ 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 }, { static_cast<uint16_t>(tlVertex.x), static_cast<uint16_t>(tlVertex.y) }));
+ vertices.emplace_back(
+ RasterProgram::layoutVertex({ brVertex.x, tlVertex.y }, { static_cast<uint16_t>(brVertex.x), static_cast<uint16_t>(tlVertex.y) }));
+ vertices.emplace_back(
+ RasterProgram::layoutVertex({ tlVertex.x, brVertex.y }, { static_cast<uint16_t>(tlVertex.x), static_cast<uint16_t>(brVertex.y) }));
+ vertices.emplace_back(
+ RasterProgram::layoutVertex({ brVertex.x, brVertex.y }, { static_cast<uint16_t>(brVertex.x), static_cast<uint16_t>(brVertex.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;
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/buckets/raster_bucket.hpp b/src/mbgl/renderer/buckets/raster_bucket.hpp
new file mode 100644
index 0000000000..3800eadec8
--- /dev/null
+++ b/src/mbgl/renderer/buckets/raster_bucket.hpp
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <mbgl/gl/index_buffer.hpp>
+#include <mbgl/gl/texture.hpp>
+#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>
+
+namespace mbgl {
+
+class RasterBucket : public Bucket {
+public:
+ RasterBucket(PremultipliedImage&&);
+ RasterBucket(std::shared_ptr<PremultipliedImage>);
+
+ void upload(gl::Context&) override;
+ bool hasData() const override;
+
+ 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
+ gl::VertexVector<RasterLayoutVertex> vertices;
+ gl::IndexVector<gl::Triangles> indices;
+ SegmentVector<RasterAttributes> segments;
+
+ optional<gl::VertexBuffer<RasterLayoutVertex>> vertexBuffer;
+ optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp
index 9b016c16f9..a3f71f1f6e 100644
--- a/src/mbgl/renderer/symbol_bucket.cpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp
@@ -1,8 +1,8 @@
-#include <mbgl/renderer/symbol_bucket.hpp>
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/renderer/render_symbol_layer.hpp>
+#include <mbgl/renderer/buckets/symbol_bucket.hpp>
+#include <mbgl/renderer/layers/render_symbol_layer.hpp>
#include <mbgl/renderer/bucket_parameters.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
+#include <mbgl/text/glyph_atlas.hpp>
namespace mbgl {
@@ -10,7 +10,8 @@ using namespace style;
SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layout_,
const std::map<std::string, std::pair<
- style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>>& layerPaintProperties,
+ style::IconPaintProperties::PossiblyEvaluated,
+ style::TextPaintProperties::PossiblyEvaluated>>& layerPaintProperties,
const style::DataDrivenPropertyValue<float>& textSize,
const style::DataDrivenPropertyValue<float>& iconSize,
float zoom,
@@ -36,14 +37,14 @@ 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));
- textSizeBinder->upload(context);
}
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));
- iconSizeBinder->upload(context);
}
if (!collisionBox.vertices.empty()) {
@@ -59,16 +60,8 @@ void SymbolBucket::upload(gl::Context& context) {
uploaded = true;
}
-void SymbolBucket::render(Painter& painter,
- PaintParameters& parameters,
- const RenderLayer& layer,
- const RenderTile& tile) {
- painter.renderSymbol(parameters, *this, *layer.as<RenderSymbolLayer>(), tile);
-}
-
bool SymbolBucket::hasData() const {
- assert(false); // Should be calling SymbolLayout::has{Text,Icon,CollisonBox}Data() instead.
- return false;
+ return hasTextData() || hasIconData() || hasCollisionBoxData();
}
bool SymbolBucket::hasTextData() const {
diff --git a/src/mbgl/renderer/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp
index a9bc868db0..32f976bcb2 100644
--- a/src/mbgl/renderer/symbol_bucket.hpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp
@@ -15,10 +15,27 @@
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_) :
+ anchorPoint(anchorPoint_), segment(segment_), lowerSize(lowerSize_), upperSize(upperSize_),
+ lineOffset(lineOffset_), placementZoom(placementZoom_), useVerticalMode(useVerticalMode_), line(std::move(line_)) {}
+ Point<float> anchorPoint;
+ uint16_t segment;
+ float lowerSize;
+ float upperSize;
+ std::array<float, 2> lineOffset;
+ float placementZoom;
+ bool useVerticalMode;
+ GeometryCoordinates line;
+ std::vector<float> glyphOffsets;
+};
+
class SymbolBucket : public Bucket {
public:
SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated,
- const std::map<std::string, std::pair<style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>>&,
+ const std::map<std::string, std::pair<style::IconPaintProperties::PossiblyEvaluated, style::TextPaintProperties::PossiblyEvaluated>>&,
const style::DataDrivenPropertyValue<float>& textSize,
const style::DataDrivenPropertyValue<float>& iconSize,
float zoom,
@@ -26,7 +43,6 @@ public:
bool iconsNeedLinear);
void upload(gl::Context&) override;
- void render(Painter&, PaintParameters&, const RenderLayer&, const RenderTile&) override;
bool hasData() const override;
bool hasTextData() const;
bool hasIconData() const;
@@ -44,10 +60,13 @@ public:
struct TextBuffer {
gl::VertexVector<SymbolLayoutVertex> vertices;
+ gl::VertexVector<SymbolDynamicLayoutAttributes::Vertex> dynamicVertices;
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::IndexBuffer<gl::Triangles>> indexBuffer;
} text;
@@ -55,10 +74,14 @@ public:
struct IconBuffer {
gl::VertexVector<SymbolLayoutVertex> vertices;
+ gl::VertexVector<SymbolDynamicLayoutAttributes::Vertex> dynamicVertices;
gl::IndexVector<gl::Triangles> triangles;
SegmentVector<SymbolIconAttributes> segments;
+ std::vector<PlacedSymbol> placedSymbols;
+ PremultipliedImage atlasImage;
optional<gl::VertexBuffer<SymbolLayoutVertex>> vertexBuffer;
+ optional<gl::VertexBuffer<SymbolDynamicLayoutAttributes::Vertex>> dynamicVertexBuffer;
optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;
} icon;
@@ -68,10 +91,9 @@ public:
SegmentVector<CollisionBoxAttributes> segments;
optional<gl::VertexBuffer<CollisionBoxVertex>> vertexBuffer;
+ optional<gl::VertexBuffer<SymbolDynamicLayoutAttributes::Vertex>> dynamicVertexBuffer;
optional<gl::IndexBuffer<gl::Lines>> indexBuffer;
} collisionBox;
-
- SpriteAtlas* spriteAtlas = nullptr;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/cross_faded_property_evaluator.cpp b/src/mbgl/renderer/cross_faded_property_evaluator.cpp
index ee3c86614f..4dff9dbf12 100644
--- a/src/mbgl/renderer/cross_faded_property_evaluator.cpp
+++ b/src/mbgl/renderer/cross_faded_property_evaluator.cpp
@@ -27,7 +27,10 @@ Faded<T> CrossFadedPropertyEvaluator<T>::calculate(const T& min, const T& mid, c
const float z = parameters.z;
const float fraction = z - std::floor(z);
const std::chrono::duration<float> d = parameters.defaultFadeDuration;
- const float t = std::min((parameters.now - parameters.zoomHistory.lastIntegerZoomTime) / d, 1.0f);
+ const float t =
+ d != std::chrono::duration<float>::zero()
+ ? std::min((parameters.now - parameters.zoomHistory.lastIntegerZoomTime) / d, 1.0f)
+ : 1.0f;
return z > parameters.zoomHistory.lastIntegerZoom
? Faded<T> { min, mid, 2.0f, 1.0f, fraction + (1.0f - fraction) * t }
diff --git a/src/mbgl/renderer/data_driven_property_evaluator.hpp b/src/mbgl/renderer/data_driven_property_evaluator.hpp
index 6406b3478b..79ecd0d495 100644
--- a/src/mbgl/renderer/data_driven_property_evaluator.hpp
+++ b/src/mbgl/renderer/data_driven_property_evaluator.hpp
@@ -24,12 +24,18 @@ public:
}
ResultType operator()(const style::CameraFunction<T>& function) const {
- return ResultType(function.evaluate(parameters.z));
+ if (!parameters.useIntegerZoom) {
+ return ResultType(function.evaluate(parameters.z));
+ } else {
+ return ResultType(function.evaluate(floor(parameters.z)));
+ }
}
template <class Function>
ResultType operator()(const Function& function) const {
- return ResultType(function);
+ auto returnFunction = function;
+ returnFunction.useIntegerZoom = parameters.useIntegerZoom;
+ return ResultType(returnFunction);
}
private:
diff --git a/src/mbgl/renderer/frame_history.cpp b/src/mbgl/renderer/frame_history.cpp
index 35e246f488..de153b6963 100644
--- a/src/mbgl/renderer/frame_history.cpp
+++ b/src/mbgl/renderer/frame_history.cpp
@@ -37,9 +37,9 @@ void FrameHistory::record(const TimePoint& now, float zoom, const Duration& dura
}
for (int16_t z = 0; z <= 255; z++) {
- std::chrono::duration<float> timeDiff = now - changeTimes[z];
- int32_t opacityChange = (duration == Milliseconds(0) ? 1 : (timeDiff / duration)) * 255;
- uint8_t opacity = z <= zoomIndex
+ 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) {
@@ -74,4 +74,8 @@ void FrameHistory::bind(gl::Context& context, uint32_t 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
index f2b11f5f41..75a8b60a71 100644
--- a/src/mbgl/renderer/frame_history.hpp
+++ b/src/mbgl/renderer/frame_history.hpp
@@ -22,6 +22,7 @@ public:
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;
diff --git a/src/mbgl/renderer/group_by_layout.cpp b/src/mbgl/renderer/group_by_layout.cpp
index df1eb7c7dd..3b02727ff8 100644
--- a/src/mbgl/renderer/group_by_layout.cpp
+++ b/src/mbgl/renderer/group_by_layout.cpp
@@ -19,13 +19,13 @@ std::string layoutKey(const RenderLayer& layer) {
writer.StartArray();
writer.Uint(static_cast<uint32_t>(layer.type));
- writer.String(layer.baseImpl.source);
- writer.String(layer.baseImpl.sourceLayer);
- writer.Double(layer.baseImpl.minZoom);
- writer.Double(layer.baseImpl.maxZoom);
- writer.Uint(static_cast<uint32_t>(layer.baseImpl.visibility));
- stringify(writer, layer.baseImpl.filter);
- layer.baseImpl.stringifyLayout(writer);
+ writer.String(layer.baseImpl->source);
+ writer.String(layer.baseImpl->sourceLayer);
+ writer.Double(layer.baseImpl->minZoom);
+ writer.Double(layer.baseImpl->maxZoom);
+ writer.Uint(static_cast<uint32_t>(layer.baseImpl->visibility));
+ stringify(writer, layer.baseImpl->filter);
+ layer.baseImpl->stringifyLayout(writer);
writer.EndArray();
return s.GetString();
diff --git a/src/mbgl/renderer/image_atlas.cpp b/src/mbgl/renderer/image_atlas.cpp
new file mode 100644
index 0000000000..8eee7c2095
--- /dev/null
+++ b/src/mbgl/renderer/image_atlas.cpp
@@ -0,0 +1,60 @@
+#include <mbgl/renderer/image_atlas.hpp>
+
+#include <mapbox/shelf-pack.hpp>
+
+namespace mbgl {
+
+static constexpr uint32_t padding = 1;
+
+ImagePosition::ImagePosition(const mapbox::Bin& bin, const style::Image::Impl& image)
+ : pixelRatio(image.pixelRatio),
+ textureRect(
+ bin.x + padding,
+ bin.y + padding,
+ bin.w - padding * 2,
+ bin.h - padding * 2
+ ) {
+}
+
+ImageAtlas makeImageAtlas(const ImageMap& images) {
+ ImageAtlas result;
+
+ mapbox::ShelfPack::ShelfPackOptions options;
+ options.autoResize = true;
+ mapbox::ShelfPack pack(0, 0, options);
+
+ for (const auto& entry : images) {
+ const style::Image::Impl& image = *entry.second;
+
+ const mapbox::Bin& bin = *pack.packOne(-1,
+ image.image.size.width + 2 * padding,
+ image.image.size.height + 2 * padding);
+
+ result.image.resize({
+ static_cast<uint32_t>(pack.width()),
+ static_cast<uint32_t>(pack.height())
+ });
+
+ PremultipliedImage::copy(image.image,
+ result.image,
+ { 0, 0 },
+ {
+ bin.x + padding,
+ bin.y + padding
+ },
+ image.image.size);
+
+ result.positions.emplace(image.id,
+ ImagePosition { bin, image });
+ }
+
+ pack.shrink();
+ result.image.resize({
+ static_cast<uint32_t>(pack.width()),
+ static_cast<uint32_t>(pack.height())
+ });
+
+ return result;
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/image_atlas.hpp b/src/mbgl/renderer/image_atlas.hpp
new file mode 100644
index 0000000000..b3cc166eff
--- /dev/null
+++ b/src/mbgl/renderer/image_atlas.hpp
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <mbgl/style/image_impl.hpp>
+#include <mbgl/util/rect.hpp>
+
+#include <mapbox/shelf-pack.hpp>
+
+#include <array>
+
+namespace mbgl {
+
+class ImagePosition {
+public:
+ ImagePosition(const mapbox::Bin&, const style::Image::Impl&);
+
+ float pixelRatio;
+ Rect<uint16_t> textureRect;
+
+ std::array<uint16_t, 2> tl() const {
+ return {{
+ textureRect.x,
+ textureRect.y
+ }};
+ }
+
+ std::array<uint16_t, 2> br() const {
+ return {{
+ static_cast<uint16_t>(textureRect.x + textureRect.w),
+ static_cast<uint16_t>(textureRect.y + textureRect.h)
+ }};
+ }
+
+ std::array<float, 2> displaySize() const {
+ return {{
+ textureRect.w / pixelRatio,
+ textureRect.h / pixelRatio,
+ }};
+ }
+};
+
+using ImagePositions = std::map<std::string, ImagePosition>;
+
+class ImageAtlas {
+public:
+ PremultipliedImage image;
+ ImagePositions positions;
+};
+
+ImageAtlas makeImageAtlas(const ImageMap&);
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/image_manager.cpp b/src/mbgl/renderer/image_manager.cpp
new file mode 100644
index 0000000000..2ef6be0c4f
--- /dev/null
+++ b/src/mbgl/renderer/image_manager.cpp
@@ -0,0 +1,184 @@
+#include <mbgl/renderer/image_manager.hpp>
+#include <mbgl/util/logging.hpp>
+#include <mbgl/gl/context.hpp>
+
+namespace mbgl {
+
+void ImageManager::setLoaded(bool loaded_) {
+ if (loaded == loaded_) {
+ return;
+ }
+
+ loaded = loaded_;
+
+ if (loaded) {
+ for (const auto& entry : requestors) {
+ notify(*entry.first, entry.second);
+ }
+ requestors.clear();
+ }
+}
+
+bool ImageManager::isLoaded() const {
+ return loaded;
+}
+
+void ImageManager::addImage(Immutable<style::Image::Impl> image_) {
+ assert(images.find(image_->id) == images.end());
+ images.emplace(image_->id, std::move(image_));
+}
+
+void ImageManager::updateImage(Immutable<style::Image::Impl> image_) {
+ removeImage(image_->id);
+ addImage(std::move(image_));
+}
+
+void ImageManager::removeImage(const std::string& id) {
+ assert(images.find(id) != images.end());
+ images.erase(id);
+
+ auto it = patterns.find(id);
+ if (it != patterns.end()) {
+ // Clear pattern from the atlas image.
+ const uint32_t x = it->second.bin->x;
+ const uint32_t y = it->second.bin->y;
+ const uint32_t w = it->second.bin->w;
+ const uint32_t h = it->second.bin->h;
+ PremultipliedImage::clear(atlasImage, { x, y }, { w, h });
+
+ shelfPack.unref(*it->second.bin);
+ patterns.erase(it);
+ }
+}
+
+const style::Image::Impl* ImageManager::getImage(const std::string& id) const {
+ const auto it = images.find(id);
+ if (it != images.end()) {
+ return it->second.get();
+ }
+ return nullptr;
+}
+
+void ImageManager::getImages(ImageRequestor& requestor, ImageRequestPair&& pair) {
+ // If the sprite has been loaded, or if all the icon dependencies are already present
+ // (i.e. if they've been addeded via runtime styling), then notify the requestor immediately.
+ // Otherwise, delay notification until the sprite is loaded. At that point, if any of the
+ // dependencies are still unavailable, we'll just assume they are permanently missing.
+ bool hasAllDependencies = true;
+ if (!isLoaded()) {
+ for (const auto& dependency : pair.first) {
+ if (images.find(dependency) == images.end()) {
+ hasAllDependencies = false;
+ }
+ }
+ }
+ if (isLoaded() || hasAllDependencies) {
+ notify(requestor, std::move(pair));
+ } else {
+ requestors.emplace(&requestor, std::move(pair));
+ }
+}
+
+void ImageManager::removeRequestor(ImageRequestor& requestor) {
+ requestors.erase(&requestor);
+}
+
+void ImageManager::notify(ImageRequestor& requestor, const ImageRequestPair& pair) const {
+ ImageMap response;
+
+ for (const auto& dependency : pair.first) {
+ auto it = images.find(dependency);
+ if (it != images.end()) {
+ response.emplace(*it);
+ }
+ }
+
+ requestor.onImagesAvailable(response, pair.second);
+}
+
+void ImageManager::dumpDebugLogs() const {
+ Log::Info(Event::General, "ImageManager::loaded: %d", loaded);
+}
+
+// When copied into the atlas texture, image data is padded by one pixel on each side. Icon
+// images are padded with fully transparent pixels, while pattern images are padded with a
+// copy of the image data wrapped from the opposite side. In both cases, this ensures the
+// correct behavior of GL_LINEAR texture sampling mode.
+static constexpr uint16_t padding = 1;
+
+static mapbox::ShelfPack::ShelfPackOptions shelfPackOptions() {
+ mapbox::ShelfPack::ShelfPackOptions options;
+ options.autoResize = true;
+ return options;
+}
+
+ImageManager::ImageManager()
+ : shelfPack(64, 64, shelfPackOptions()) {
+}
+
+ImageManager::~ImageManager() = default;
+
+optional<ImagePosition> ImageManager::getPattern(const std::string& id) {
+ auto it = patterns.find(id);
+ if (it != patterns.end()) {
+ return it->second.position;
+ }
+
+ const style::Image::Impl* image = getImage(id);
+ if (!image) {
+ return {};
+ }
+
+ const uint16_t width = image->image.size.width + padding * 2;
+ const uint16_t height = image->image.size.height + padding * 2;
+
+ mapbox::Bin* bin = shelfPack.packOne(-1, width, height);
+ if (!bin) {
+ return {};
+ }
+
+ atlasImage.resize(getPixelSize());
+
+ const PremultipliedImage& src = image->image;
+
+ const uint32_t x = bin->x + padding;
+ const uint32_t y = bin->y + padding;
+ const uint32_t w = src.size.width;
+ const uint32_t h = src.size.height;
+
+ PremultipliedImage::copy(src, atlasImage, { 0, 0 }, { x, y }, { w, h });
+
+ // Add 1 pixel wrapped padding on each side of the image.
+ PremultipliedImage::copy(src, atlasImage, { 0, h - 1 }, { x, y - 1 }, { w, 1 }); // T
+ PremultipliedImage::copy(src, atlasImage, { 0, 0 }, { x, y + h }, { w, 1 }); // B
+ PremultipliedImage::copy(src, atlasImage, { w - 1, 0 }, { x - 1, y }, { 1, h }); // L
+ PremultipliedImage::copy(src, atlasImage, { 0, 0 }, { x + w, y }, { 1, h }); // R
+
+ dirty = true;
+
+ return patterns.emplace(id, Pattern { bin, { *bin, *image } }).first->second.position;
+}
+
+Size ImageManager::getPixelSize() const {
+ return Size {
+ static_cast<uint32_t>(shelfPack.width()),
+ static_cast<uint32_t>(shelfPack.height())
+ };
+}
+
+void ImageManager::upload(gl::Context& context, gl::TextureUnit unit) {
+ if (!atlasTexture) {
+ atlasTexture = context.createTexture(atlasImage, unit);
+ } else if (dirty) {
+ context.updateTexture(*atlasTexture, atlasImage, unit);
+ }
+
+ dirty = false;
+}
+
+void ImageManager::bind(gl::Context& context, gl::TextureUnit unit) {
+ upload(context, unit);
+ context.bindTexture(*atlasTexture, unit, gl::TextureFilter::Linear);
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/image_manager.hpp b/src/mbgl/renderer/image_manager.hpp
new file mode 100644
index 0000000000..f72ba9fb53
--- /dev/null
+++ b/src/mbgl/renderer/image_manager.hpp
@@ -0,0 +1,91 @@
+#pragma once
+
+#include <mbgl/style/image_impl.hpp>
+#include <mbgl/renderer/image_atlas.hpp>
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/immutable.hpp>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/gl/texture.hpp>
+
+#include <mapbox/shelf-pack.hpp>
+
+#include <set>
+#include <string>
+
+namespace mbgl {
+
+namespace gl {
+class Context;
+} // namespace gl
+
+class ImageRequestor {
+public:
+ virtual ~ImageRequestor() = default;
+ virtual void onImagesAvailable(ImageMap, uint64_t imageCorrelationID) = 0;
+};
+
+/*
+ ImageManager does two things:
+
+ 1. Tracks requests for icon images from tile workers and sends responses when the requests are fulfilled.
+ 2. Builds a texture atlas for pattern images.
+
+ These are disparate responsibilities and should eventually be handled by different classes. When we implement
+ data-driven support for `*-pattern`, we'll likely use per-bucket pattern atlases, and that would be a good time
+ to refactor this.
+*/
+class ImageManager : public util::noncopyable {
+public:
+ ImageManager();
+ ~ImageManager();
+
+ void setLoaded(bool);
+ bool isLoaded() const;
+
+ void dumpDebugLogs() const;
+
+ const style::Image::Impl* getImage(const std::string&) const;
+
+ void addImage(Immutable<style::Image::Impl>);
+ void updateImage(Immutable<style::Image::Impl>);
+ void removeImage(const std::string&);
+
+ void getImages(ImageRequestor&, ImageRequestPair&&);
+ void removeRequestor(ImageRequestor&);
+
+private:
+ void notify(ImageRequestor&, const ImageRequestPair&) const;
+
+ bool loaded = false;
+
+ std::unordered_map<ImageRequestor*, ImageRequestPair> requestors;
+ ImageMap images;
+
+// Pattern stuff
+public:
+ optional<ImagePosition> getPattern(const std::string& name);
+
+ void bind(gl::Context&, gl::TextureUnit unit);
+ void upload(gl::Context&, gl::TextureUnit unit);
+
+ Size getPixelSize() const;
+
+ // Only for use in tests.
+ const PremultipliedImage& getAtlasImage() const {
+ return atlasImage;
+ }
+
+private:
+ struct Pattern {
+ mapbox::Bin* bin;
+ ImagePosition position;
+ };
+
+ mapbox::ShelfPack shelfPack;
+ std::unordered_map<std::string, Pattern> patterns;
+ PremultipliedImage atlasImage;
+ mbgl::optional<gl::Texture> atlasTexture;
+ bool dirty = true;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/layers/render_background_layer.cpp b/src/mbgl/renderer/layers/render_background_layer.cpp
new file mode 100644
index 0000000000..9fddba3f74
--- /dev/null
+++ b/src/mbgl/renderer/layers/render_background_layer.cpp
@@ -0,0 +1,115 @@
+#include <mbgl/renderer/layers/render_background_layer.hpp>
+#include <mbgl/style/layers/background_layer_impl.hpp>
+#include <mbgl/renderer/bucket.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/image_manager.hpp>
+#include <mbgl/renderer/render_static_data.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/fill_program.hpp>
+#include <mbgl/util/tile_cover.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+RenderBackgroundLayer::RenderBackgroundLayer(Immutable<style::BackgroundLayer::Impl> _impl)
+ : RenderLayer(style::LayerType::Background, _impl),
+ unevaluated(impl().paint.untransitioned()) {
+}
+
+const style::BackgroundLayer::Impl& RenderBackgroundLayer::impl() const {
+ return static_cast<const style::BackgroundLayer::Impl&>(*baseImpl);
+}
+
+std::unique_ptr<Bucket> RenderBackgroundLayer::createBucket(const BucketParameters &,
+ const std::vector<const RenderLayer *> &) const {
+ assert(false);
+ return nullptr;
+}
+
+void RenderBackgroundLayer::transition(const TransitionParameters &parameters) {
+ unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated));
+}
+
+void RenderBackgroundLayer::evaluate(const PropertyEvaluationParameters &parameters) {
+ evaluated = unevaluated.evaluate(parameters);
+
+ passes = evaluated.get<style::BackgroundOpacity>() > 0 ? RenderPass::Translucent
+ : RenderPass::None;
+}
+
+bool RenderBackgroundLayer::hasTransition() const {
+ return unevaluated.hasTransition();
+}
+
+void RenderBackgroundLayer::render(PaintParameters& parameters, RenderSource*) {
+ // Note that for bottommost layers without a pattern, the background color is drawn with
+ // glClear rather than this method.
+
+ style::FillPaintProperties::PossiblyEvaluated properties;
+ properties.get<FillPattern>() = evaluated.get<BackgroundPattern>();
+ properties.get<FillOpacity>() = { evaluated.get<BackgroundOpacity>() };
+ properties.get<FillColor>() = { evaluated.get<BackgroundColor>() };
+
+ const FillProgram::PaintPropertyBinders paintAttibuteData(properties, 0);
+
+ if (!evaluated.get<BackgroundPattern>().to.empty()) {
+ optional<ImagePosition> imagePosA = parameters.imageManager.getPattern(evaluated.get<BackgroundPattern>().from);
+ optional<ImagePosition> imagePosB = parameters.imageManager.getPattern(evaluated.get<BackgroundPattern>().to);
+
+ if (!imagePosA || !imagePosB)
+ return;
+
+ parameters.imageManager.bind(parameters.context, 0);
+
+ for (const auto& tileID : util::tileCover(parameters.state, parameters.state.getIntegerZoom())) {
+ parameters.programs.fillPattern.get(properties).draw(
+ parameters.context,
+ gl::Triangles(),
+ parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ gl::StencilMode::disabled(),
+ parameters.colorModeForRenderPass(),
+ FillPatternUniforms::values(
+ parameters.matrixForTile(tileID),
+ parameters.context.viewport.getCurrentValue().size,
+ parameters.imageManager.getPixelSize(),
+ *imagePosA,
+ *imagePosB,
+ evaluated.get<BackgroundPattern>(),
+ tileID,
+ parameters.state
+ ),
+ parameters.staticData.tileVertexBuffer,
+ parameters.staticData.quadTriangleIndexBuffer,
+ parameters.staticData.tileTriangleSegments,
+ paintAttibuteData,
+ properties,
+ parameters.state.getZoom(),
+ getID()
+ );
+ }
+ } else {
+ for (const auto& tileID : util::tileCover(parameters.state, parameters.state.getIntegerZoom())) {
+ parameters.programs.fill.get(properties).draw(
+ parameters.context,
+ gl::Triangles(),
+ parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ gl::StencilMode::disabled(),
+ parameters.colorModeForRenderPass(),
+ FillProgram::UniformValues {
+ uniforms::u_matrix::Value{ parameters.matrixForTile(tileID) },
+ uniforms::u_world::Value{ parameters.context.viewport.getCurrentValue().size },
+ },
+ parameters.staticData.tileVertexBuffer,
+ parameters.staticData.quadTriangleIndexBuffer,
+ parameters.staticData.tileTriangleSegments,
+ paintAttibuteData,
+ properties,
+ parameters.state.getZoom(),
+ getID()
+ );
+ }
+ }
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_background_layer.hpp b/src/mbgl/renderer/layers/render_background_layer.hpp
index b1f709953f..a619670ee4 100644
--- a/src/mbgl/renderer/render_background_layer.hpp
+++ b/src/mbgl/renderer/layers/render_background_layer.hpp
@@ -1,30 +1,28 @@
#pragma once
#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/style/layers/background_layer.hpp>
+#include <mbgl/style/layers/background_layer_impl.hpp>
#include <mbgl/style/layers/background_layer_properties.hpp>
namespace mbgl {
class RenderBackgroundLayer: public RenderLayer {
public:
-
- RenderBackgroundLayer(const style::BackgroundLayer::Impl&);
+ RenderBackgroundLayer(Immutable<style::BackgroundLayer::Impl>);
~RenderBackgroundLayer() final = default;
- std::unique_ptr<RenderLayer> clone() const override;
-
- void cascade(const CascadeParameters&) override;
+ void transition(const TransitionParameters&) override;
void evaluate(const PropertyEvaluationParameters&) override;
bool hasTransition() const override;
+ void render(PaintParameters&, RenderSource*) override;
std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const override;
// Paint properties
style::BackgroundPaintProperties::Unevaluated unevaluated;
- style::BackgroundPaintProperties::Evaluated evaluated;
+ style::BackgroundPaintProperties::PossiblyEvaluated evaluated;
- const style::BackgroundLayer::Impl* const impl;
+ const style::BackgroundLayer::Impl& impl() const;
};
template <>
@@ -32,4 +30,4 @@ inline bool RenderLayer::is<RenderBackgroundLayer>() const {
return type == style::LayerType::Background;
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp
new file mode 100644
index 0000000000..e7b022f3ee
--- /dev/null
+++ b/src/mbgl/renderer/layers/render_circle_layer.cpp
@@ -0,0 +1,120 @@
+#include <mbgl/renderer/layers/render_circle_layer.hpp>
+#include <mbgl/renderer/buckets/circle_bucket.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/circle_program.hpp>
+#include <mbgl/tile/tile.hpp>
+#include <mbgl/style/layers/circle_layer_impl.hpp>
+#include <mbgl/geometry/feature_index.hpp>
+#include <mbgl/util/math.hpp>
+#include <mbgl/util/intersection_tests.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+RenderCircleLayer::RenderCircleLayer(Immutable<style::CircleLayer::Impl> _impl)
+ : RenderLayer(style::LayerType::Circle, _impl),
+ unevaluated(impl().paint.untransitioned()) {
+}
+
+const style::CircleLayer::Impl& RenderCircleLayer::impl() const {
+ return static_cast<const style::CircleLayer::Impl&>(*baseImpl);
+}
+
+std::unique_ptr<Bucket> RenderCircleLayer::createBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) const {
+ return std::make_unique<CircleBucket>(parameters, layers);
+}
+
+void RenderCircleLayer::transition(const TransitionParameters& parameters) {
+ unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated));
+}
+
+void RenderCircleLayer::evaluate(const PropertyEvaluationParameters& parameters) {
+ evaluated = unevaluated.evaluate(parameters);
+
+ passes = ((evaluated.get<style::CircleRadius>().constantOr(1) > 0 ||
+ evaluated.get<style::CircleStrokeWidth>().constantOr(1) > 0)
+ && (evaluated.get<style::CircleColor>().constantOr(Color::black()).a > 0 ||
+ evaluated.get<style::CircleStrokeColor>().constantOr(Color::black()).a > 0)
+ && (evaluated.get<style::CircleOpacity>().constantOr(1) > 0 ||
+ evaluated.get<style::CircleStrokeOpacity>().constantOr(1) > 0))
+ ? RenderPass::Translucent : RenderPass::None;
+}
+
+bool RenderCircleLayer::hasTransition() const {
+ return unevaluated.hasTransition();
+}
+
+void RenderCircleLayer::render(PaintParameters& parameters, RenderSource*) {
+ if (parameters.pass == RenderPass::Opaque) {
+ return;
+ }
+
+ const bool scaleWithMap = evaluated.get<CirclePitchScale>() == CirclePitchScaleType::Map;
+ const bool pitchWithMap = evaluated.get<CirclePitchAlignment>() == AlignmentType::Map;
+
+ for (const RenderTile& tile : renderTiles) {
+ assert(dynamic_cast<CircleBucket*>(tile.tile.getBucket(*baseImpl)));
+ CircleBucket& bucket = *reinterpret_cast<CircleBucket*>(tile.tile.getBucket(*baseImpl));
+
+ parameters.programs.circle.get(evaluated).draw(
+ parameters.context,
+ gl::Triangles(),
+ parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ parameters.mapMode == MapMode::Still
+ ? parameters.stencilModeForClipping(tile.clip)
+ : gl::StencilMode::disabled(),
+ parameters.colorModeForRenderPass(),
+ CircleProgram::UniformValues {
+ uniforms::u_matrix::Value{
+ tile.translatedMatrix(evaluated.get<CircleTranslate>(),
+ evaluated.get<CircleTranslateAnchor>(),
+ parameters.state)
+ },
+ uniforms::u_scale_with_map::Value{ scaleWithMap },
+ uniforms::u_extrude_scale::Value{ pitchWithMap
+ ? std::array<float, 2> {{
+ tile.id.pixelsToTileUnits(1, parameters.state.getZoom()),
+ tile.id.pixelsToTileUnits(1, parameters.state.getZoom()) }}
+ : parameters.pixelsToGLUnits },
+ uniforms::u_camera_to_center_distance::Value{ parameters.state.getCameraToCenterDistance() },
+ uniforms::u_pitch_with_map::Value{ pitchWithMap }
+ },
+ *bucket.vertexBuffer,
+ *bucket.indexBuffer,
+ bucket.segments,
+ bucket.paintPropertyBinders.at(getID()),
+ evaluated,
+ parameters.state.getZoom(),
+ getID()
+ );
+ }
+}
+
+bool RenderCircleLayer::queryIntersectsFeature(
+ const GeometryCoordinates& queryGeometry,
+ const GeometryTileFeature& feature,
+ const float zoom,
+ const float bearing,
+ const float pixelsToTileUnits) const {
+
+ // Translate query geometry
+ auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
+ queryGeometry,
+ evaluated.get<style::CircleTranslate>(),
+ evaluated.get<style::CircleTranslateAnchor>(),
+ bearing,
+ pixelsToTileUnits);
+
+ // Evaluate function
+ auto circleRadius = evaluated.get<style::CircleRadius>()
+ .evaluate(feature, zoom, style::CircleRadius::defaultValue())
+ * pixelsToTileUnits;
+
+ // Test intersection
+ return util::polygonIntersectsBufferedMultiPoint(translatedQueryGeometry.value_or(queryGeometry), feature.getGeometries(), circleRadius);
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_circle_layer.hpp b/src/mbgl/renderer/layers/render_circle_layer.hpp
index 3b82b5c988..f31715f98f 100644
--- a/src/mbgl/renderer/render_circle_layer.hpp
+++ b/src/mbgl/renderer/layers/render_circle_layer.hpp
@@ -1,22 +1,20 @@
#pragma once
#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/style/layers/circle_layer.hpp>
+#include <mbgl/style/layers/circle_layer_impl.hpp>
#include <mbgl/style/layers/circle_layer_properties.hpp>
namespace mbgl {
class RenderCircleLayer: public RenderLayer {
public:
-
- RenderCircleLayer(const style::CircleLayer::Impl&);
+ RenderCircleLayer(Immutable<style::CircleLayer::Impl>);
~RenderCircleLayer() final = default;
- std::unique_ptr<RenderLayer> clone() const override;
-
- void cascade(const CascadeParameters&) override;
+ void transition(const TransitionParameters&) override;
void evaluate(const PropertyEvaluationParameters&) override;
bool hasTransition() const override;
+ void render(PaintParameters&, RenderSource*) override;
bool queryIntersectsFeature(
const GeometryCoordinates&,
@@ -29,9 +27,9 @@ public:
// Paint properties
style::CirclePaintProperties::Unevaluated unevaluated;
- style::CirclePaintProperties::Evaluated evaluated;
+ style::CirclePaintProperties::PossiblyEvaluated evaluated;
- const style::CircleLayer::Impl* const impl;
+ const style::CircleLayer::Impl& impl() const;
};
template <>
@@ -39,4 +37,4 @@ inline bool RenderLayer::is<RenderCircleLayer>() const {
return type == style::LayerType::Circle;
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/renderer/layers/render_custom_layer.cpp b/src/mbgl/renderer/layers/render_custom_layer.cpp
new file mode 100644
index 0000000000..7ece3970da
--- /dev/null
+++ b/src/mbgl/renderer/layers/render_custom_layer.cpp
@@ -0,0 +1,81 @@
+#include <mbgl/renderer/layers/render_custom_layer.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/backend_scope.hpp>
+#include <mbgl/renderer/renderer_backend.hpp>
+#include <mbgl/renderer/bucket.hpp>
+#include <mbgl/style/layers/custom_layer_impl.hpp>
+#include <mbgl/map/transform_state.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+RenderCustomLayer::RenderCustomLayer(Immutable<style::CustomLayer::Impl> _impl)
+ : RenderLayer(LayerType::Custom, _impl) {
+}
+
+RenderCustomLayer::~RenderCustomLayer() {
+ assert(BackendScope::exists());
+ if (initialized) {
+ if (contextDestroyed && impl().contextLostFn ) {
+ impl().contextLostFn(impl().context);
+ } else if (!contextDestroyed && impl().deinitializeFn) {
+ impl().deinitializeFn(impl().context);
+ }
+ }
+}
+
+const CustomLayer::Impl& RenderCustomLayer::impl() const {
+ return static_cast<const CustomLayer::Impl&>(*baseImpl);
+}
+
+void RenderCustomLayer::evaluate(const PropertyEvaluationParameters&) {
+ passes = RenderPass::Translucent;
+}
+
+bool RenderCustomLayer::hasTransition() const {
+ return false;
+}
+
+std::unique_ptr<Bucket> RenderCustomLayer::createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const {
+ assert(false);
+ return nullptr;
+}
+
+void RenderCustomLayer::render(PaintParameters& paintParameters, RenderSource*) {
+ if (!initialized) {
+ assert(impl().initializeFn);
+ impl().initializeFn(impl().context);
+ initialized = true;
+ }
+
+ gl::Context& context = paintParameters.context;
+ const TransformState& state = paintParameters.state;
+
+ // Reset GL state to a known state so the CustomLayer always has a clean slate.
+ context.bindVertexArray = 0;
+ context.setDepthMode(paintParameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly));
+ context.setStencilMode(gl::StencilMode::disabled());
+ context.setColorMode(paintParameters.colorModeForRenderPass());
+
+ CustomLayerRenderParameters parameters;
+
+ parameters.width = state.getSize().width;
+ parameters.height = state.getSize().height;
+ parameters.latitude = state.getLatLng().latitude();
+ parameters.longitude = state.getLatLng().longitude();
+ parameters.zoom = state.getZoom();
+ parameters.bearing = -state.getAngle() * util::RAD2DEG;
+ parameters.pitch = state.getPitch();
+ parameters.fieldOfView = state.getFieldOfView();
+
+ assert(impl().renderFn);
+ impl().renderFn(impl().context, parameters);
+
+ // Reset the view back to our original one, just in case the CustomLayer changed
+ // the viewport or Framebuffer.
+ paintParameters.backend.bind();
+ context.setDirtyState();
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_custom_layer.hpp b/src/mbgl/renderer/layers/render_custom_layer.hpp
index c3af6c77b2..32ed9da8da 100644
--- a/src/mbgl/renderer/render_custom_layer.hpp
+++ b/src/mbgl/renderer/layers/render_custom_layer.hpp
@@ -1,25 +1,31 @@
#pragma once
#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/style/layers/custom_layer.hpp>
+#include <mbgl/style/layers/custom_layer_impl.hpp>
namespace mbgl {
class RenderCustomLayer: public RenderLayer {
public:
+ RenderCustomLayer(Immutable<style::CustomLayer::Impl>);
+ ~RenderCustomLayer() final;
- RenderCustomLayer(const style::CustomLayer::Impl&);
- ~RenderCustomLayer() final = default;
-
- std::unique_ptr<RenderLayer> clone() const override;
-
- void cascade(const CascadeParameters&) final {}
+ void transition(const TransitionParameters&) final {}
void evaluate(const PropertyEvaluationParameters&) override;
bool hasTransition() const override;
std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const final;
+ void render(PaintParameters&, RenderSource*) final;
+
+ const style::CustomLayer::Impl& impl() const;
- const style::CustomLayer::Impl* const impl;
+ void markContextDestroyed() {
+ contextDestroyed = true;
+ };
+
+private:
+ bool initialized = false;
+ bool contextDestroyed = false;
};
template <>
@@ -27,4 +33,4 @@ inline bool RenderLayer::is<RenderCustomLayer>() const {
return type == style::LayerType::Custom;
}
-}
+} // namespace mbgl
diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
new file mode 100644
index 0000000000..fbd6160e8a
--- /dev/null
+++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
@@ -0,0 +1,167 @@
+#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp>
+#include <mbgl/renderer/buckets/fill_extrusion_bucket.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/image_manager.hpp>
+#include <mbgl/renderer/render_static_data.hpp>
+#include <mbgl/renderer/renderer_backend.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/fill_extrusion_program.hpp>
+#include <mbgl/tile/tile.hpp>
+#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp>
+#include <mbgl/geometry/feature_index.hpp>
+#include <mbgl/util/math.hpp>
+#include <mbgl/util/intersection_tests.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+RenderFillExtrusionLayer::RenderFillExtrusionLayer(Immutable<style::FillExtrusionLayer::Impl> _impl)
+ : RenderLayer(style::LayerType::FillExtrusion, _impl),
+ unevaluated(impl().paint.untransitioned()) {
+}
+
+const style::FillExtrusionLayer::Impl& RenderFillExtrusionLayer::impl() const {
+ return static_cast<const style::FillExtrusionLayer::Impl&>(*baseImpl);
+}
+
+std::unique_ptr<Bucket> RenderFillExtrusionLayer::createBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) const {
+ return std::make_unique<FillExtrusionBucket>(parameters, layers);
+}
+
+void RenderFillExtrusionLayer::transition(const TransitionParameters& parameters) {
+ unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated));
+}
+
+void RenderFillExtrusionLayer::evaluate(const PropertyEvaluationParameters& parameters) {
+ evaluated = unevaluated.evaluate(parameters);
+
+ passes = (evaluated.get<style::FillExtrusionOpacity>() > 0)
+ ? (RenderPass::Translucent | RenderPass::Pass3D)
+ : RenderPass::None;
+}
+
+bool RenderFillExtrusionLayer::hasTransition() const {
+ return unevaluated.hasTransition();
+}
+
+void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource*) {
+ if (parameters.pass == RenderPass::Opaque) {
+ return;
+ }
+
+ if (parameters.pass == RenderPass::Pass3D) {
+ const auto& size = parameters.staticData.backendSize;
+
+ if (!renderTexture || renderTexture->getSize() != size) {
+ renderTexture = OffscreenTexture(parameters.context, size, *parameters.staticData.depthRenderbuffer);
+ }
+
+ renderTexture->bind();
+
+ optional<float> depthClearValue = {};
+ if (parameters.staticData.depthRenderbuffer->needsClearing()) depthClearValue = 1.0;
+ // Flag the depth buffer as no longer needing to be cleared for the remainder of this pass.
+ parameters.staticData.depthRenderbuffer->shouldClear(false);
+
+ parameters.context.setStencilMode(gl::StencilMode::disabled());
+ parameters.context.clear(Color{ 0.0f, 0.0f, 0.0f, 0.0f }, depthClearValue, {});
+
+ if (evaluated.get<FillExtrusionPattern>().from.empty()) {
+ for (const RenderTile& tile : renderTiles) {
+ assert(dynamic_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl)));
+ FillExtrusionBucket& bucket =
+ *reinterpret_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl));
+
+ parameters.programs.fillExtrusion.get(evaluated).draw(
+ parameters.context, gl::Triangles(),
+ parameters.depthModeFor3D(gl::DepthMode::ReadWrite),
+ gl::StencilMode::disabled(), parameters.colorModeForRenderPass(),
+ FillExtrusionUniforms::values(
+ tile.translatedClipMatrix(evaluated.get<FillExtrusionTranslate>(),
+ evaluated.get<FillExtrusionTranslateAnchor>(),
+ parameters.state),
+ parameters.state, parameters.evaluatedLight),
+ *bucket.vertexBuffer, *bucket.indexBuffer, bucket.triangleSegments,
+ bucket.paintPropertyBinders.at(getID()), evaluated, parameters.state.getZoom(),
+ getID());
+ }
+ } else {
+ optional<ImagePosition> imagePosA =
+ parameters.imageManager.getPattern(evaluated.get<FillExtrusionPattern>().from);
+ optional<ImagePosition> imagePosB =
+ parameters.imageManager.getPattern(evaluated.get<FillExtrusionPattern>().to);
+
+ if (!imagePosA || !imagePosB) {
+ return;
+ }
+
+ parameters.imageManager.bind(parameters.context, 0);
+
+ for (const RenderTile& tile : renderTiles) {
+ assert(dynamic_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl)));
+ FillExtrusionBucket& bucket =
+ *reinterpret_cast<FillExtrusionBucket*>(tile.tile.getBucket(*baseImpl));
+
+ parameters.programs.fillExtrusionPattern.get(evaluated).draw(
+ parameters.context, gl::Triangles(),
+ parameters.depthModeFor3D(gl::DepthMode::ReadWrite),
+ gl::StencilMode::disabled(), parameters.colorModeForRenderPass(),
+ FillExtrusionPatternUniforms::values(
+ tile.translatedClipMatrix(evaluated.get<FillExtrusionTranslate>(),
+ evaluated.get<FillExtrusionTranslateAnchor>(),
+ parameters.state),
+ parameters.imageManager.getPixelSize(), *imagePosA, *imagePosB,
+ evaluated.get<FillExtrusionPattern>(), tile.id, parameters.state,
+ -std::pow(2, tile.id.canonical.z) / util::tileSize / 8.0f,
+ parameters.evaluatedLight),
+ *bucket.vertexBuffer, *bucket.indexBuffer, bucket.triangleSegments,
+ bucket.paintPropertyBinders.at(getID()), evaluated, parameters.state.getZoom(),
+ getID());
+ }
+ }
+
+ } else if (parameters.pass == RenderPass::Translucent) {
+ parameters.context.bindTexture(renderTexture->getTexture());
+
+ const auto& size = parameters.staticData.backendSize;
+
+ mat4 viewportMat;
+ matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1);
+
+ const Properties<>::PossiblyEvaluated properties;
+
+ parameters.programs.extrusionTexture.draw(
+ parameters.context, gl::Triangles(), gl::DepthMode::disabled(),
+ gl::StencilMode::disabled(), parameters.colorModeForRenderPass(),
+ ExtrusionTextureProgram::UniformValues{
+ uniforms::u_matrix::Value{ viewportMat }, uniforms::u_world::Value{ size },
+ uniforms::u_image::Value{ 0 },
+ uniforms::u_opacity::Value{ evaluated.get<FillExtrusionOpacity>() } },
+ parameters.staticData.extrusionTextureVertexBuffer,
+ parameters.staticData.quadTriangleIndexBuffer,
+ parameters.staticData.extrusionTextureSegments,
+ ExtrusionTextureProgram::PaintPropertyBinders{ properties, 0 }, properties,
+ parameters.state.getZoom(), getID());
+ }
+}
+
+bool RenderFillExtrusionLayer::queryIntersectsFeature(
+ const GeometryCoordinates& queryGeometry,
+ const GeometryTileFeature& feature,
+ const float,
+ const float bearing,
+ const float pixelsToTileUnits) const {
+
+ auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
+ queryGeometry,
+ evaluated.get<style::FillExtrusionTranslate>(),
+ evaluated.get<style::FillExtrusionTranslateAnchor>(),
+ bearing,
+ pixelsToTileUnits);
+
+ return util::polygonIntersectsMultiPolygon(translatedQueryGeometry.value_or(queryGeometry), feature.getGeometries());
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_fill_extrusion_layer.hpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp
index bd66d8e3b1..838494cf91 100644
--- a/src/mbgl/renderer/render_fill_extrusion_layer.hpp
+++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp
@@ -1,22 +1,22 @@
#pragma once
#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/style/layers/fill_extrusion_layer.hpp>
+#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp>
#include <mbgl/style/layers/fill_extrusion_layer_properties.hpp>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/util/offscreen_texture.hpp>
namespace mbgl {
class RenderFillExtrusionLayer: public RenderLayer {
public:
-
- RenderFillExtrusionLayer(const style::FillExtrusionLayer::Impl&);
+ RenderFillExtrusionLayer(Immutable<style::FillExtrusionLayer::Impl>);
~RenderFillExtrusionLayer() final = default;
- std::unique_ptr<RenderLayer> clone() const override;
-
- void cascade(const CascadeParameters&) override;
+ void transition(const TransitionParameters&) override;
void evaluate(const PropertyEvaluationParameters&) override;
bool hasTransition() const override;
+ void render(PaintParameters&, RenderSource*) override;
bool queryIntersectsFeature(
const GeometryCoordinates&,
@@ -29,9 +29,11 @@ public:
// Paint properties
style::FillExtrusionPaintProperties::Unevaluated unevaluated;
- style::FillExtrusionPaintProperties::Evaluated evaluated;
+ style::FillExtrusionPaintProperties::PossiblyEvaluated evaluated;
+
+ const style::FillExtrusionLayer::Impl& impl() const;
- const style::FillExtrusionLayer::Impl* const impl;
+ optional<OffscreenTexture> renderTexture;
};
template <>
diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp
new file mode 100644
index 0000000000..22cb9563c1
--- /dev/null
+++ b/src/mbgl/renderer/layers/render_fill_layer.cpp
@@ -0,0 +1,205 @@
+#include <mbgl/renderer/layers/render_fill_layer.hpp>
+#include <mbgl/renderer/buckets/fill_bucket.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/image_manager.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/fill_program.hpp>
+#include <mbgl/tile/tile.hpp>
+#include <mbgl/style/layers/fill_layer_impl.hpp>
+#include <mbgl/geometry/feature_index.hpp>
+#include <mbgl/util/math.hpp>
+#include <mbgl/util/intersection_tests.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+RenderFillLayer::RenderFillLayer(Immutable<style::FillLayer::Impl> _impl)
+ : RenderLayer(style::LayerType::Fill, _impl),
+ unevaluated(impl().paint.untransitioned()) {
+}
+
+const style::FillLayer::Impl& RenderFillLayer::impl() const {
+ return static_cast<const style::FillLayer::Impl&>(*baseImpl);
+}
+
+std::unique_ptr<Bucket> RenderFillLayer::createBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) const {
+ return std::make_unique<FillBucket>(parameters, layers);
+}
+
+void RenderFillLayer::transition(const TransitionParameters& parameters) {
+ unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated));
+}
+
+void RenderFillLayer::evaluate(const PropertyEvaluationParameters& parameters) {
+ evaluated = unevaluated.evaluate(parameters);
+
+ if (unevaluated.get<style::FillOutlineColor>().isUndefined()) {
+ evaluated.get<style::FillOutlineColor>() = evaluated.get<style::FillColor>();
+ }
+
+ passes = RenderPass::None;
+
+ if (evaluated.get<style::FillAntialias>()) {
+ passes |= RenderPass::Translucent;
+ }
+
+ if (!unevaluated.get<style::FillPattern>().isUndefined()
+ || evaluated.get<style::FillColor>().constantOr(Color()).a < 1.0f
+ || evaluated.get<style::FillOpacity>().constantOr(0) < 1.0f) {
+ passes |= RenderPass::Translucent;
+ } else {
+ passes |= RenderPass::Opaque;
+ }
+}
+
+bool RenderFillLayer::hasTransition() const {
+ return unevaluated.hasTransition();
+}
+
+void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) {
+ if (evaluated.get<FillPattern>().from.empty()) {
+ for (const RenderTile& tile : renderTiles) {
+ assert(dynamic_cast<FillBucket*>(tile.tile.getBucket(*baseImpl)));
+ FillBucket& bucket = *reinterpret_cast<FillBucket*>(tile.tile.getBucket(*baseImpl));
+
+ auto draw = [&] (auto& program,
+ const auto& drawMode,
+ const auto& depthMode,
+ const auto& indexBuffer,
+ const auto& segments) {
+ program.get(evaluated).draw(
+ parameters.context,
+ drawMode,
+ depthMode,
+ parameters.stencilModeForClipping(tile.clip),
+ parameters.colorModeForRenderPass(),
+ FillProgram::UniformValues {
+ uniforms::u_matrix::Value{
+ tile.translatedMatrix(evaluated.get<FillTranslate>(),
+ evaluated.get<FillTranslateAnchor>(),
+ parameters.state)
+ },
+ uniforms::u_world::Value{ parameters.context.viewport.getCurrentValue().size },
+ },
+ *bucket.vertexBuffer,
+ indexBuffer,
+ segments,
+ bucket.paintPropertyBinders.at(getID()),
+ evaluated,
+ parameters.state.getZoom(),
+ getID()
+ );
+ };
+
+ // Only draw the fill when it's opaque and we're drawing opaque fragments,
+ // or when it's translucent and we're drawing translucent fragments.
+ if ((evaluated.get<FillColor>().constantOr(Color()).a >= 1.0f
+ && evaluated.get<FillOpacity>().constantOr(0) >= 1.0f) == (parameters.pass == RenderPass::Opaque)) {
+ draw(parameters.programs.fill,
+ gl::Triangles(),
+ parameters.depthModeForSublayer(1, parameters.pass == RenderPass::Opaque
+ ? gl::DepthMode::ReadWrite
+ : gl::DepthMode::ReadOnly),
+ *bucket.triangleIndexBuffer,
+ bucket.triangleSegments);
+ }
+
+ if (evaluated.get<FillAntialias>() && parameters.pass == RenderPass::Translucent) {
+ draw(parameters.programs.fillOutline,
+ gl::Lines{ 2.0f },
+ parameters.depthModeForSublayer(
+ unevaluated.get<FillOutlineColor>().isUndefined() ? 2 : 0,
+ gl::DepthMode::ReadOnly),
+ *bucket.lineIndexBuffer,
+ bucket.lineSegments);
+ }
+ }
+ } else {
+ if (parameters.pass != RenderPass::Translucent) {
+ return;
+ }
+
+ optional<ImagePosition> imagePosA = parameters.imageManager.getPattern(evaluated.get<FillPattern>().from);
+ optional<ImagePosition> imagePosB = parameters.imageManager.getPattern(evaluated.get<FillPattern>().to);
+
+ if (!imagePosA || !imagePosB) {
+ return;
+ }
+
+ parameters.imageManager.bind(parameters.context, 0);
+
+ for (const RenderTile& tile : renderTiles) {
+ assert(dynamic_cast<FillBucket*>(tile.tile.getBucket(*baseImpl)));
+ FillBucket& bucket = *reinterpret_cast<FillBucket*>(tile.tile.getBucket(*baseImpl));
+
+ auto draw = [&] (auto& program,
+ const auto& drawMode,
+ const auto& depthMode,
+ const auto& indexBuffer,
+ const auto& segments) {
+ program.get(evaluated).draw(
+ parameters.context,
+ drawMode,
+ depthMode,
+ parameters.stencilModeForClipping(tile.clip),
+ parameters.colorModeForRenderPass(),
+ FillPatternUniforms::values(
+ tile.translatedMatrix(evaluated.get<FillTranslate>(),
+ evaluated.get<FillTranslateAnchor>(),
+ parameters.state),
+ parameters.context.viewport.getCurrentValue().size,
+ parameters.imageManager.getPixelSize(),
+ *imagePosA,
+ *imagePosB,
+ evaluated.get<FillPattern>(),
+ tile.id,
+ parameters.state
+ ),
+ *bucket.vertexBuffer,
+ indexBuffer,
+ segments,
+ bucket.paintPropertyBinders.at(getID()),
+ evaluated,
+ parameters.state.getZoom(),
+ getID()
+ );
+ };
+
+ draw(parameters.programs.fillPattern,
+ gl::Triangles(),
+ parameters.depthModeForSublayer(1, gl::DepthMode::ReadWrite),
+ *bucket.triangleIndexBuffer,
+ bucket.triangleSegments);
+
+ if (evaluated.get<FillAntialias>() && unevaluated.get<FillOutlineColor>().isUndefined()) {
+ draw(parameters.programs.fillOutlinePattern,
+ gl::Lines { 2.0f },
+ parameters.depthModeForSublayer(2, gl::DepthMode::ReadOnly),
+ *bucket.lineIndexBuffer,
+ bucket.lineSegments);
+ }
+ }
+ }
+}
+
+bool RenderFillLayer::queryIntersectsFeature(
+ const GeometryCoordinates& queryGeometry,
+ const GeometryTileFeature& feature,
+ const float,
+ const float bearing,
+ const float pixelsToTileUnits) const {
+
+ auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
+ queryGeometry,
+ evaluated.get<style::FillTranslate>(),
+ evaluated.get<style::FillTranslateAnchor>(),
+ bearing,
+ pixelsToTileUnits);
+
+ return util::polygonIntersectsMultiPolygon(translatedQueryGeometry.value_or(queryGeometry), feature.getGeometries());
+}
+
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_fill_layer.hpp b/src/mbgl/renderer/layers/render_fill_layer.hpp
index 8080cf289b..a51865698f 100644
--- a/src/mbgl/renderer/render_fill_layer.hpp
+++ b/src/mbgl/renderer/layers/render_fill_layer.hpp
@@ -1,22 +1,20 @@
#pragma once
#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/style/layers/fill_layer.hpp>
+#include <mbgl/style/layers/fill_layer_impl.hpp>
#include <mbgl/style/layers/fill_layer_properties.hpp>
namespace mbgl {
class RenderFillLayer: public RenderLayer {
public:
-
- RenderFillLayer(const style::FillLayer::Impl&);
+ RenderFillLayer(Immutable<style::FillLayer::Impl>);
~RenderFillLayer() final = default;
- std::unique_ptr<RenderLayer> clone() const override;
-
- void cascade(const CascadeParameters&) override;
+ void transition(const TransitionParameters&) override;
void evaluate(const PropertyEvaluationParameters&) override;
bool hasTransition() const override;
+ void render(PaintParameters&, RenderSource*) override;
bool queryIntersectsFeature(
const GeometryCoordinates&,
@@ -29,9 +27,9 @@ public:
// Paint properties
style::FillPaintProperties::Unevaluated unevaluated;
- style::FillPaintProperties::Evaluated evaluated;
+ style::FillPaintProperties::PossiblyEvaluated evaluated;
- const style::FillLayer::Impl* const impl;
+ const style::FillLayer::Impl& impl() const;
};
template <>
diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp
new file mode 100644
index 0000000000..1b4a1c0ff7
--- /dev/null
+++ b/src/mbgl/renderer/layers/render_line_layer.cpp
@@ -0,0 +1,204 @@
+#include <mbgl/renderer/layers/render_line_layer.hpp>
+#include <mbgl/renderer/buckets/line_bucket.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/image_manager.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/line_program.hpp>
+#include <mbgl/geometry/line_atlas.hpp>
+#include <mbgl/tile/tile.hpp>
+#include <mbgl/style/layers/line_layer_impl.hpp>
+#include <mbgl/geometry/feature_index.hpp>
+#include <mbgl/util/math.hpp>
+#include <mbgl/util/intersection_tests.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+RenderLineLayer::RenderLineLayer(Immutable<style::LineLayer::Impl> _impl)
+ : RenderLayer(style::LayerType::Line, _impl),
+ unevaluated(impl().paint.untransitioned()) {
+}
+
+const style::LineLayer::Impl& RenderLineLayer::impl() const {
+ return static_cast<const style::LineLayer::Impl&>(*baseImpl);
+}
+
+std::unique_ptr<Bucket> RenderLineLayer::createBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) const {
+ return std::make_unique<LineBucket>(parameters, layers, impl().layout);
+}
+
+void RenderLineLayer::transition(const TransitionParameters& parameters) {
+ unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated));
+}
+
+void RenderLineLayer::evaluate(const PropertyEvaluationParameters& parameters) {
+ style::Properties<LineFloorwidth>::Unevaluated extra(unevaluated.get<style::LineWidth>());
+
+ auto dashArrayParams = parameters;
+ dashArrayParams.useIntegerZoom = true;
+
+ evaluated = RenderLinePaintProperties::PossiblyEvaluated(
+ unevaluated.evaluate(parameters).concat(extra.evaluate(dashArrayParams)));
+
+ passes = (evaluated.get<style::LineOpacity>().constantOr(1.0) > 0
+ && evaluated.get<style::LineColor>().constantOr(Color::black()).a > 0
+ && evaluated.get<style::LineWidth>().constantOr(1.0) > 0)
+ ? RenderPass::Translucent : RenderPass::None;
+}
+
+bool RenderLineLayer::hasTransition() const {
+ return unevaluated.hasTransition();
+}
+
+void RenderLineLayer::render(PaintParameters& parameters, RenderSource*) {
+ if (parameters.pass == RenderPass::Opaque) {
+ return;
+ }
+
+ for (const RenderTile& tile : renderTiles) {
+ assert(dynamic_cast<LineBucket*>(tile.tile.getBucket(*baseImpl)));
+ LineBucket& bucket = *reinterpret_cast<LineBucket*>(tile.tile.getBucket(*baseImpl));
+
+ auto draw = [&] (auto& program, auto&& uniformValues) {
+ program.get(evaluated).draw(
+ parameters.context,
+ gl::Triangles(),
+ parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ parameters.stencilModeForClipping(tile.clip),
+ parameters.colorModeForRenderPass(),
+ std::move(uniformValues),
+ *bucket.vertexBuffer,
+ *bucket.indexBuffer,
+ bucket.segments,
+ bucket.paintPropertyBinders.at(getID()),
+ evaluated,
+ parameters.state.getZoom(),
+ getID()
+ );
+ };
+
+ if (!evaluated.get<LineDasharray>().from.empty()) {
+ const LinePatternCap cap = bucket.layout.get<LineCap>() == LineCapType::Round
+ ? LinePatternCap::Round : LinePatternCap::Square;
+ LinePatternPos posA = parameters.lineAtlas.getDashPosition(evaluated.get<LineDasharray>().from, cap);
+ LinePatternPos posB = parameters.lineAtlas.getDashPosition(evaluated.get<LineDasharray>().to, cap);
+
+ parameters.lineAtlas.bind(parameters.context, 0);
+
+ draw(parameters.programs.lineSDF,
+ LineSDFProgram::uniformValues(
+ evaluated,
+ parameters.pixelRatio,
+ tile,
+ parameters.state,
+ parameters.pixelsToGLUnits,
+ posA,
+ posB,
+ parameters.lineAtlas.getSize().width));
+
+ } else if (!evaluated.get<LinePattern>().from.empty()) {
+ optional<ImagePosition> posA = parameters.imageManager.getPattern(evaluated.get<LinePattern>().from);
+ optional<ImagePosition> posB = parameters.imageManager.getPattern(evaluated.get<LinePattern>().to);
+
+ if (!posA || !posB)
+ return;
+
+ parameters.imageManager.bind(parameters.context, 0);
+
+ draw(parameters.programs.linePattern,
+ LinePatternProgram::uniformValues(
+ evaluated,
+ tile,
+ parameters.state,
+ parameters.pixelsToGLUnits,
+ parameters.imageManager.getPixelSize(),
+ *posA,
+ *posB));
+
+ } else {
+ draw(parameters.programs.line,
+ LineProgram::uniformValues(
+ evaluated,
+ tile,
+ parameters.state,
+ parameters.pixelsToGLUnits));
+ }
+ }
+}
+
+optional<GeometryCollection> offsetLine(const GeometryCollection& rings, const double offset) {
+ if (offset == 0) return {};
+
+ GeometryCollection newRings;
+ Point<double> zero(0, 0);
+ for (const auto& ring : rings) {
+ newRings.emplace_back();
+ auto& newRing = newRings.back();
+
+ for (auto i = ring.begin(); i != ring.end(); i++) {
+ auto& p = *i;
+
+ Point<double> aToB = i == ring.begin() ?
+ zero :
+ util::perp(util::unit(convertPoint<double>(p - *(i - 1))));
+ Point<double> bToC = i + 1 == ring.end() ?
+ zero :
+ util::perp(util::unit(convertPoint<double>(*(i + 1) - p)));
+ Point<double> extrude = util::unit(aToB + bToC);
+
+ const double cosHalfAngle = extrude.x * bToC.x + extrude.y * bToC.y;
+ extrude *= (1.0 / cosHalfAngle);
+
+ newRing.push_back(convertPoint<int16_t>(extrude * offset) + p);
+ }
+ }
+
+ return newRings;
+}
+
+bool RenderLineLayer::queryIntersectsFeature(
+ const GeometryCoordinates& queryGeometry,
+ const GeometryTileFeature& feature,
+ const float zoom,
+ const float bearing,
+ const float pixelsToTileUnits) const {
+
+ // Translate query geometry
+ auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
+ queryGeometry,
+ evaluated.get<style::LineTranslate>(),
+ evaluated.get<style::LineTranslateAnchor>(),
+ bearing,
+ pixelsToTileUnits);
+
+ // Evaluate function
+ auto offset = evaluated.get<style::LineOffset>()
+ .evaluate(feature, zoom, style::LineOffset::defaultValue()) * pixelsToTileUnits;
+
+ // Apply offset to geometry
+ auto offsetGeometry = offsetLine(feature.getGeometries(), offset);
+
+ // Test intersection
+ const float halfWidth = getLineWidth(feature, zoom) / 2.0 * pixelsToTileUnits;
+ return util::polygonIntersectsBufferedMultiLine(
+ translatedQueryGeometry.value_or(queryGeometry),
+ offsetGeometry.value_or(feature.getGeometries()),
+ halfWidth);
+}
+
+float RenderLineLayer::getLineWidth(const GeometryTileFeature& feature, const float zoom) const {
+ float lineWidth = evaluated.get<style::LineWidth>()
+ .evaluate(feature, zoom, style::LineWidth::defaultValue());
+ float gapWidth = evaluated.get<style::LineGapWidth>()
+ .evaluate(feature, zoom, style::LineGapWidth::defaultValue());
+ if (gapWidth) {
+ return gapWidth + 2 * lineWidth;
+ } else {
+ return lineWidth;
+ }
+}
+
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_line_layer.hpp b/src/mbgl/renderer/layers/render_line_layer.hpp
index 6d6fecc227..8bf7e2329d 100644
--- a/src/mbgl/renderer/render_line_layer.hpp
+++ b/src/mbgl/renderer/layers/render_line_layer.hpp
@@ -1,22 +1,29 @@
#pragma once
#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/style/layers/line_layer.hpp>
+#include <mbgl/style/layers/line_layer_impl.hpp>
#include <mbgl/style/layers/line_layer_properties.hpp>
+#include <mbgl/programs/uniforms.hpp>
namespace mbgl {
+struct LineFloorwidth : style::DataDrivenPaintProperty<float, attributes::a_floorwidth, uniforms::u_floorwidth> {
+ static float defaultValue() { return 1; }
+};
+
+class RenderLinePaintProperties : public style::ConcatenateProperties<
+ style::LinePaintProperties::PropertyTypes,
+ TypeList<LineFloorwidth>>::Type {};
+
class RenderLineLayer: public RenderLayer {
public:
-
- RenderLineLayer(const style::LineLayer::Impl&);
+ RenderLineLayer(Immutable<style::LineLayer::Impl>);
~RenderLineLayer() final = default;
- std::unique_ptr<RenderLayer> clone() const override;
-
- void cascade(const CascadeParameters&) override;
+ void transition(const TransitionParameters&) override;
void evaluate(const PropertyEvaluationParameters&) override;
bool hasTransition() const override;
+ void render(PaintParameters&, RenderSource*) override;
bool queryIntersectsFeature(
const GeometryCoordinates&,
@@ -29,16 +36,12 @@ public:
// Paint properties
style::LinePaintProperties::Unevaluated unevaluated;
- style::LinePaintProperties::Evaluated evaluated;
-
- const style::LineLayer::Impl* const impl;
+ RenderLinePaintProperties::PossiblyEvaluated evaluated;
- // Special case
- float dashLineWidth = 1;
+ const style::LineLayer::Impl& impl() const;
private:
float getLineWidth(const GeometryTileFeature&, const float) const;
-
};
template <>
diff --git a/src/mbgl/renderer/layers/render_raster_layer.cpp b/src/mbgl/renderer/layers/render_raster_layer.cpp
new file mode 100644
index 0000000000..06616d90e5
--- /dev/null
+++ b/src/mbgl/renderer/layers/render_raster_layer.cpp
@@ -0,0 +1,155 @@
+#include <mbgl/renderer/layers/render_raster_layer.hpp>
+#include <mbgl/renderer/buckets/raster_bucket.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/sources/render_image_source.hpp>
+#include <mbgl/renderer/render_static_data.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/programs/raster_program.hpp>
+#include <mbgl/tile/tile.hpp>
+#include <mbgl/style/layers/raster_layer_impl.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+RenderRasterLayer::RenderRasterLayer(Immutable<style::RasterLayer::Impl> _impl)
+ : RenderLayer(style::LayerType::Raster, _impl),
+ unevaluated(impl().paint.untransitioned()) {
+}
+
+const style::RasterLayer::Impl& RenderRasterLayer::impl() const {
+ return static_cast<const style::RasterLayer::Impl&>(*baseImpl);
+}
+
+std::unique_ptr<Bucket> RenderRasterLayer::createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const {
+ assert(false);
+ return nullptr;
+}
+
+void RenderRasterLayer::transition(const TransitionParameters& parameters) {
+ unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated));
+}
+
+void RenderRasterLayer::evaluate(const PropertyEvaluationParameters& parameters) {
+ evaluated = unevaluated.evaluate(parameters);
+
+ passes = evaluated.get<style::RasterOpacity>() > 0 ? RenderPass::Translucent : RenderPass::None;
+}
+
+bool RenderRasterLayer::hasTransition() const {
+ return unevaluated.hasTransition();
+}
+
+static float saturationFactor(float saturation) {
+ if (saturation > 0) {
+ return 1 - 1 / (1.001 - saturation);
+ } else {
+ return -saturation;
+ }
+}
+
+static float contrastFactor(float contrast) {
+ if (contrast > 0) {
+ return 1 / (1 - contrast);
+ } else {
+ return 1 + contrast;
+ }
+}
+
+static std::array<float, 3> spinWeights(float spin) {
+ spin *= util::DEG2RAD;
+ float s = std::sin(spin);
+ float c = std::cos(spin);
+ std::array<float, 3> spin_weights = {{
+ (2 * c + 1) / 3,
+ (-std::sqrt(3.0f) * s - c + 1) / 3,
+ (std::sqrt(3.0f) * s - c + 1) / 3
+ }};
+ return spin_weights;
+}
+
+void RenderRasterLayer::render(PaintParameters& parameters, RenderSource* source) {
+ if (parameters.pass != RenderPass::Translucent)
+ return;
+
+ auto draw = [&] (const mat4& matrix,
+ const auto& vertexBuffer,
+ const auto& indexBuffer,
+ const auto& segments) {
+ parameters.programs.raster.draw(
+ parameters.context,
+ gl::Triangles(),
+ parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly),
+ gl::StencilMode::disabled(),
+ parameters.colorModeForRenderPass(),
+ RasterProgram::UniformValues {
+ uniforms::u_matrix::Value{ matrix },
+ uniforms::u_image0::Value{ 0 },
+ uniforms::u_image1::Value{ 1 },
+ uniforms::u_opacity::Value{ evaluated.get<RasterOpacity>() },
+ uniforms::u_fade_t::Value{ 1 },
+ uniforms::u_brightness_low::Value{ evaluated.get<RasterBrightnessMin>() },
+ uniforms::u_brightness_high::Value{ evaluated.get<RasterBrightnessMax>() },
+ uniforms::u_saturation_factor::Value{ saturationFactor(evaluated.get<RasterSaturation>()) },
+ uniforms::u_contrast_factor::Value{ contrastFactor(evaluated.get<RasterContrast>()) },
+ uniforms::u_spin_weights::Value{ spinWeights(evaluated.get<RasterHueRotate>()) },
+ uniforms::u_buffer_scale::Value{ 1.0f },
+ uniforms::u_scale_parent::Value{ 1.0f },
+ uniforms::u_tl_parent::Value{ std::array<float, 2> {{ 0.0f, 0.0f }} },
+ },
+ vertexBuffer,
+ indexBuffer,
+ segments,
+ RasterProgram::PaintPropertyBinders { evaluated, 0 },
+ evaluated,
+ parameters.state.getZoom(),
+ getID()
+ );
+ };
+
+ if (RenderImageSource* imageSource = source->as<RenderImageSource>()) {
+ if (imageSource->isEnabled() && imageSource->isLoaded() && !imageSource->bucket->needsUpload()) {
+ RasterBucket& bucket = *imageSource->bucket;
+
+ assert(bucket.texture);
+ parameters.context.bindTexture(*bucket.texture, 0, gl::TextureFilter::Linear);
+ parameters.context.bindTexture(*bucket.texture, 1, gl::TextureFilter::Linear);
+
+ for (auto matrix_ : imageSource->matrices) {
+ draw(matrix_,
+ *bucket.vertexBuffer,
+ *bucket.indexBuffer,
+ bucket.segments);
+ }
+ }
+ } else {
+ for (const RenderTile& tile : renderTiles) {
+ assert(dynamic_cast<RasterBucket*>(tile.tile.getBucket(*baseImpl)));
+ RasterBucket& bucket = *reinterpret_cast<RasterBucket*>(tile.tile.getBucket(*baseImpl));
+
+ if (!bucket.hasData())
+ continue;
+
+ assert(bucket.texture);
+ parameters.context.bindTexture(*bucket.texture, 0, gl::TextureFilter::Linear);
+ parameters.context.bindTexture(*bucket.texture, 1, gl::TextureFilter::Linear);
+
+ 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);
+ }
+ }
+ }
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_raster_layer.hpp b/src/mbgl/renderer/layers/render_raster_layer.hpp
index 3ffeb8febf..87de316f7c 100644
--- a/src/mbgl/renderer/render_raster_layer.hpp
+++ b/src/mbgl/renderer/layers/render_raster_layer.hpp
@@ -1,30 +1,29 @@
#pragma once
#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/style/layers/raster_layer.hpp>
+#include <mbgl/style/layers/raster_layer_impl.hpp>
#include <mbgl/style/layers/raster_layer_properties.hpp>
namespace mbgl {
class RenderRasterLayer: public RenderLayer {
public:
-
- RenderRasterLayer(const style::RasterLayer::Impl&);
+ RenderRasterLayer(Immutable<style::RasterLayer::Impl>);
~RenderRasterLayer() final = default;
- std::unique_ptr<RenderLayer> clone() const override;
-
- void cascade(const CascadeParameters&) override;
+ void transition(const TransitionParameters&) override;
void evaluate(const PropertyEvaluationParameters&) override;
bool hasTransition() const override;
+ void render(PaintParameters&, RenderSource*) override;
+
std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const override;
// Paint properties
style::RasterPaintProperties::Unevaluated unevaluated;
- style::RasterPaintProperties::Evaluated evaluated;
+ style::RasterPaintProperties::PossiblyEvaluated evaluated;
- const style::RasterLayer::Impl* const impl;
+ const style::RasterLayer::Impl& impl() const;
};
template <>
diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp
new file mode 100644
index 0000000000..1376e8a3d8
--- /dev/null
+++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp
@@ -0,0 +1,325 @@
+#include <mbgl/renderer/layers/render_symbol_layer.hpp>
+#include <mbgl/renderer/buckets/symbol_bucket.hpp>
+#include <mbgl/renderer/bucket_parameters.hpp>
+#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>
+#include <mbgl/programs/collision_box_program.hpp>
+#include <mbgl/tile/tile.hpp>
+#include <mbgl/tile/geometry_tile.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
+#include <mbgl/style/layers/symbol_layer_impl.hpp>
+#include <mbgl/layout/symbol_layout.hpp>
+#include <mbgl/layout/symbol_projection.hpp>
+#include <mbgl/util/math.hpp>
+
+#include <cmath>
+
+namespace mbgl {
+
+using namespace style;
+
+RenderSymbolLayer::RenderSymbolLayer(Immutable<style::SymbolLayer::Impl> _impl)
+ : RenderLayer(style::LayerType::Symbol, _impl),
+ unevaluated(impl().paint.untransitioned()) {
+}
+
+const style::SymbolLayer::Impl& RenderSymbolLayer::impl() const {
+ return static_cast<const style::SymbolLayer::Impl&>(*baseImpl);
+}
+
+std::unique_ptr<Bucket> RenderSymbolLayer::createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const {
+ assert(false); // Should be calling createLayout() instead.
+ return nullptr;
+}
+
+std::unique_ptr<SymbolLayout> RenderSymbolLayer::createLayout(const BucketParameters& parameters,
+ const std::vector<const RenderLayer*>& group,
+ std::unique_ptr<GeometryTileLayer> layer,
+ GlyphDependencies& glyphDependencies,
+ ImageDependencies& imageDependencies) const {
+ return std::make_unique<SymbolLayout>(parameters,
+ group,
+ std::move(layer),
+ imageDependencies,
+ glyphDependencies);
+}
+
+void RenderSymbolLayer::transition(const TransitionParameters& parameters) {
+ unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated));
+}
+
+void RenderSymbolLayer::evaluate(const PropertyEvaluationParameters& parameters) {
+ evaluated = unevaluated.evaluate(parameters);
+
+ auto hasIconOpacity = evaluated.get<style::IconColor>().constantOr(Color::black()).a > 0 ||
+ evaluated.get<style::IconHaloColor>().constantOr(Color::black()).a > 0;
+ auto hasTextOpacity = evaluated.get<style::TextColor>().constantOr(Color::black()).a > 0 ||
+ evaluated.get<style::TextHaloColor>().constantOr(Color::black()).a > 0;
+
+ passes = ((evaluated.get<style::IconOpacity>().constantOr(1) > 0 && hasIconOpacity && iconSize > 0)
+ || (evaluated.get<style::TextOpacity>().constantOr(1) > 0 && hasTextOpacity && textSize > 0))
+ ? RenderPass::Translucent : RenderPass::None;
+}
+
+bool RenderSymbolLayer::hasTransition() const {
+ return unevaluated.hasTransition();
+}
+
+void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) {
+ if (parameters.pass == RenderPass::Opaque) {
+ return;
+ }
+
+ for (const RenderTile& tile : renderTiles) {
+ assert(dynamic_cast<SymbolBucket*>(tile.tile.getBucket(*baseImpl)));
+ SymbolBucket& bucket = *reinterpret_cast<SymbolBucket*>(tile.tile.getBucket(*baseImpl));
+
+ const auto& layout = bucket.layout;
+
+ parameters.frameHistory.bind(parameters.context, 1);
+
+ auto draw = [&] (auto& program,
+ auto&& uniformValues,
+ const auto& buffers,
+ const auto& symbolSizeBinder,
+ const SymbolPropertyValues& values_,
+ 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(),
+ parameters.colorModeForRenderPass(),
+ std::move(uniformValues),
+ *buffers.vertexBuffer,
+ *buffers.dynamicVertexBuffer,
+ *symbolSizeBinder,
+ *buffers.indexBuffer,
+ buffers.segments,
+ binders,
+ paintProperties,
+ parameters.state.getZoom(),
+ getID()
+ );
+ };
+
+ assert(dynamic_cast<GeometryTile*>(&tile.tile));
+ GeometryTile& geometryTile = static_cast<GeometryTile&>(tile.tile);
+
+ if (bucket.hasIconData()) {
+ auto values = iconPropertyValues(layout);
+ auto paintPropertyValues = iconPaintProperties();
+
+ const bool alongLine = layout.get<SymbolPlacement>() == SymbolPlacementType::Line &&
+ layout.get<IconRotationAlignment>() == AlignmentType::Map;
+
+ if (alongLine) {
+ reprojectLineLabels(bucket.icon.dynamicVertices,
+ bucket.icon.placedSymbols,
+ tile.matrix,
+ values,
+ tile,
+ *bucket.iconSizeBinder,
+ parameters.state,
+ parameters.frameHistory);
+
+ parameters.context.updateVertexBuffer(*bucket.icon.dynamicVertexBuffer, std::move(bucket.icon.dynamicVertices));
+ }
+
+ const bool iconScaled = layout.get<IconSize>().constantOr(1.0) != 1.0 || bucket.iconsNeedLinear;
+ const bool iconTransformed = values.rotationAlignment == AlignmentType::Map || parameters.state.getPitch() != 0;
+
+ parameters.context.bindTexture(*geometryTile.iconAtlasTexture, 0,
+ bucket.sdfIcons || parameters.state.isChanging() || iconScaled || iconTransformed
+ ? gl::TextureFilter::Linear : gl::TextureFilter::Nearest);
+
+ const Size texsize = geometryTile.iconAtlasTexture->size;
+
+ if (bucket.sdfIcons) {
+ if (values.hasHalo) {
+ draw(parameters.programs.symbolIconSDF,
+ SymbolSDFIconProgram::uniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, SymbolSDFPart::Halo),
+ bucket.icon,
+ bucket.iconSizeBinder,
+ values,
+ bucket.paintPropertyBinders.at(getID()).first,
+ paintPropertyValues);
+ }
+
+ if (values.hasFill) {
+ draw(parameters.programs.symbolIconSDF,
+ SymbolSDFIconProgram::uniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, SymbolSDFPart::Fill),
+ bucket.icon,
+ bucket.iconSizeBinder,
+ values,
+ bucket.paintPropertyBinders.at(getID()).first,
+ paintPropertyValues);
+ }
+ } else {
+ draw(parameters.programs.symbolIcon,
+ SymbolIconProgram::uniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state),
+ bucket.icon,
+ bucket.iconSizeBinder,
+ values,
+ bucket.paintPropertyBinders.at(getID()).first,
+ paintPropertyValues);
+ }
+ }
+
+ if (bucket.hasTextData()) {
+ parameters.context.bindTexture(*geometryTile.glyphAtlasTexture, 0, gl::TextureFilter::Linear);
+
+ auto values = textPropertyValues(layout);
+ auto paintPropertyValues = textPaintProperties();
+
+ const bool alongLine = layout.get<SymbolPlacement>() == SymbolPlacementType::Line &&
+ layout.get<TextRotationAlignment>() == AlignmentType::Map;
+
+ if (alongLine) {
+ reprojectLineLabels(bucket.text.dynamicVertices,
+ bucket.text.placedSymbols,
+ tile.matrix,
+ values,
+ tile,
+ *bucket.textSizeBinder,
+ parameters.state,
+ parameters.frameHistory);
+
+ parameters.context.updateVertexBuffer(*bucket.text.dynamicVertexBuffer, std::move(bucket.text.dynamicVertices));
+ }
+
+ const Size texsize = geometryTile.glyphAtlasTexture->size;
+
+ if (values.hasHalo) {
+ draw(parameters.programs.symbolGlyph,
+ SymbolSDFTextProgram::uniformValues(true, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, SymbolSDFPart::Halo),
+ bucket.text,
+ bucket.textSizeBinder,
+ values,
+ bucket.paintPropertyBinders.at(getID()).second,
+ paintPropertyValues);
+ }
+
+ if (values.hasFill) {
+ draw(parameters.programs.symbolGlyph,
+ SymbolSDFTextProgram::uniformValues(true, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, SymbolSDFPart::Fill),
+ bucket.text,
+ bucket.textSizeBinder,
+ values,
+ bucket.paintPropertyBinders.at(getID()).second,
+ paintPropertyValues);
+ }
+ }
+
+ if (bucket.hasCollisionBoxData()) {
+ static const style::Properties<>::PossiblyEvaluated properties {};
+ static const CollisionBoxProgram::PaintPropertyBinders paintAttributeData(properties, 0);
+
+ parameters.programs.collisionBox.draw(
+ parameters.context,
+ gl::Lines { 1.0f },
+ gl::DepthMode::disabled(),
+ parameters.stencilModeForClipping(tile.clip),
+ 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 }
+ },
+ *bucket.collisionBox.vertexBuffer,
+ *bucket.collisionBox.indexBuffer,
+ bucket.collisionBox.segments,
+ paintAttributeData,
+ properties,
+ parameters.state.getZoom(),
+ getID()
+ );
+ }
+ }
+}
+
+style::IconPaintProperties::PossiblyEvaluated RenderSymbolLayer::iconPaintProperties() const {
+ return style::IconPaintProperties::PossiblyEvaluated {
+ evaluated.get<style::IconOpacity>(),
+ evaluated.get<style::IconColor>(),
+ evaluated.get<style::IconHaloColor>(),
+ evaluated.get<style::IconHaloWidth>(),
+ evaluated.get<style::IconHaloBlur>(),
+ evaluated.get<style::IconTranslate>(),
+ evaluated.get<style::IconTranslateAnchor>()
+ };
+}
+
+style::TextPaintProperties::PossiblyEvaluated RenderSymbolLayer::textPaintProperties() const {
+ return style::TextPaintProperties::PossiblyEvaluated {
+ evaluated.get<style::TextOpacity>(),
+ evaluated.get<style::TextColor>(),
+ evaluated.get<style::TextHaloColor>(),
+ evaluated.get<style::TextHaloWidth>(),
+ evaluated.get<style::TextHaloBlur>(),
+ evaluated.get<style::TextTranslate>(),
+ evaluated.get<style::TextTranslateAnchor>()
+ };
+}
+
+
+style::SymbolPropertyValues RenderSymbolLayer::iconPropertyValues(const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) const {
+ return style::SymbolPropertyValues {
+ layout_.get<style::IconPitchAlignment>(),
+ layout_.get<style::IconRotationAlignment>(),
+ layout_.get<style::IconKeepUpright>(),
+ evaluated.get<style::IconTranslate>(),
+ evaluated.get<style::IconTranslateAnchor>(),
+ evaluated.get<style::IconHaloColor>().constantOr(Color::black()).a > 0 &&
+ evaluated.get<style::IconHaloWidth>().constantOr(1),
+ evaluated.get<style::IconColor>().constantOr(Color::black()).a > 0,
+ 10.0f
+ };
+}
+
+style::SymbolPropertyValues RenderSymbolLayer::textPropertyValues(const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) const {
+ // We hide line labels with viewport alignment as they move into the distance
+ // because the approximations we use for drawing their glyphs get progressively worse
+ // The "1.5" here means we start hiding them when the distance from the label
+ // to the camera is 50% greater than the distance from the center of the map
+ // to the camera. Depending on viewport properties, you might expect this to filter
+ // the top third of the screen at pitch 60, and do almost nothing at pitch 45
+ // "10" is effectively infinite at any pitch we support
+ const bool limitMaxDistance =
+ layout_.get<style::SymbolPlacement>() == style::SymbolPlacementType::Line
+ && layout_.get<style::TextRotationAlignment>() == style::AlignmentType::Map
+ && layout_.get<style::TextPitchAlignment>() == style::AlignmentType::Viewport;
+
+ return style::SymbolPropertyValues {
+ layout_.get<style::TextPitchAlignment>(),
+ layout_.get<style::TextRotationAlignment>(),
+ layout_.get<style::TextKeepUpright>(),
+ evaluated.get<style::TextTranslate>(),
+ evaluated.get<style::TextTranslateAnchor>(),
+ evaluated.get<style::TextHaloColor>().constantOr(Color::black()).a > 0 &&
+ evaluated.get<style::TextHaloWidth>().constantOr(1),
+ evaluated.get<style::TextColor>().constantOr(Color::black()).a > 0,
+ limitMaxDistance ? 1.5f : 10.0f
+ };
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_symbol_layer.hpp b/src/mbgl/renderer/layers/render_symbol_layer.hpp
index 80ffd95a06..83709b5122 100644
--- a/src/mbgl/renderer/render_symbol_layer.hpp
+++ b/src/mbgl/renderer/layers/render_symbol_layer.hpp
@@ -2,8 +2,8 @@
#include <mbgl/text/glyph.hpp>
#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/style/layers/symbol_layer.hpp>
+#include <mbgl/style/image_impl.hpp>
+#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
namespace mbgl {
@@ -13,7 +13,7 @@ namespace style {
// {icon,text}-specific paint-property packs for use in the symbol Programs.
// Since each program deals either with icons or text, using a smaller property set
// lets us avoid unnecessarily binding attributes for properties the program wouldn't use.
-class IconPaintProperties : public PaintProperties<
+class IconPaintProperties : public Properties<
IconOpacity,
IconColor,
IconHaloColor,
@@ -23,7 +23,7 @@ class IconPaintProperties : public PaintProperties<
IconTranslateAnchor
> {};
-class TextPaintProperties : public PaintProperties<
+class TextPaintProperties : public Properties<
TextOpacity,
TextColor,
TextHaloColor,
@@ -40,17 +40,16 @@ public:
// Layout
AlignmentType pitchAlignment;
AlignmentType rotationAlignment;
- PossiblyEvaluatedPropertyValue<float> layoutSize;
+ bool keepUpright;
// Paint
std::array<float, 2> translate;
TranslateAnchorType translateAnchor;
- float paintSize;
-
- float sdfScale; // Constant (1.0 or 24.0)
bool hasHalo;
bool hasFill;
+
+ float maxCameraDistance; // 1.5 for road labels, or 10 (essentially infinite) for everything else
};
} // namespace style
@@ -61,33 +60,35 @@ class GeometryTileLayer;
class RenderSymbolLayer: public RenderLayer {
public:
- RenderSymbolLayer(const style::SymbolLayer::Impl&);
+ RenderSymbolLayer(Immutable<style::SymbolLayer::Impl>);
~RenderSymbolLayer() final = default;
- std::unique_ptr<RenderLayer> clone() const override;
-
- void cascade(const CascadeParameters&) override;
+ void transition(const TransitionParameters&) override;
void evaluate(const PropertyEvaluationParameters&) override;
bool hasTransition() const override;
+ void render(PaintParameters&, RenderSource*) override;
- style::IconPaintProperties::Evaluated iconPaintProperties() const;
- style::TextPaintProperties::Evaluated textPaintProperties() const;
+ style::IconPaintProperties::PossiblyEvaluated iconPaintProperties() const;
+ style::TextPaintProperties::PossiblyEvaluated textPaintProperties() const;
style::SymbolPropertyValues iconPropertyValues(const style::SymbolLayoutProperties::PossiblyEvaluated&) const;
style::SymbolPropertyValues textPropertyValues(const style::SymbolLayoutProperties::PossiblyEvaluated&) const;
std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const override;
- std::unique_ptr<SymbolLayout> createLayout(const BucketParameters&, const std::vector<const RenderLayer*>&,
- const GeometryTileLayer&, GlyphDependencies&, IconDependencies&) const;
+ std::unique_ptr<SymbolLayout> createLayout(const BucketParameters&,
+ const std::vector<const RenderLayer*>&,
+ std::unique_ptr<GeometryTileLayer>,
+ GlyphDependencies&,
+ ImageDependencies&) const;
// Paint properties
style::SymbolPaintProperties::Unevaluated unevaluated;
- style::SymbolPaintProperties::Evaluated evaluated;
+ style::SymbolPaintProperties::PossiblyEvaluated evaluated;
float iconSize = 1.0f;
float textSize = 16.0f;
- const style::SymbolLayer::Impl* const impl;
+ const style::SymbolLayer::Impl& impl() const;
};
template <>
diff --git a/src/mbgl/renderer/paint_parameters.cpp b/src/mbgl/renderer/paint_parameters.cpp
new file mode 100644
index 0000000000..299db844bc
--- /dev/null
+++ b/src/mbgl/renderer/paint_parameters.cpp
@@ -0,0 +1,98 @@
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/update_parameters.hpp>
+#include <mbgl/renderer/render_static_data.hpp>
+#include <mbgl/map/transform_state.hpp>
+
+namespace mbgl {
+
+PaintParameters::PaintParameters(gl::Context& context_,
+ float pixelRatio_,
+ GLContextMode contextMode_,
+ RendererBackend& backend_,
+ const UpdateParameters& updateParameters,
+ const EvaluatedLight& evaluatedLight_,
+ RenderStaticData& staticData_,
+ FrameHistory& frameHistory_,
+ ImageManager& imageManager_,
+ LineAtlas& lineAtlas_)
+ : context(context_),
+ backend(backend_),
+ state(updateParameters.transformState),
+ evaluatedLight(evaluatedLight_),
+ staticData(staticData_),
+ frameHistory(frameHistory_),
+ imageManager(imageManager_),
+ lineAtlas(lineAtlas_),
+ mapMode(updateParameters.mode),
+ debugOptions(updateParameters.debugOptions),
+ contextMode(contextMode_),
+ timePoint(updateParameters.timePoint),
+ pixelRatio(pixelRatio_),
+#ifndef NDEBUG
+ programs((debugOptions & MapDebugOptions::Overdraw) ? staticData_.overdrawPrograms : staticData_.programs)
+#else
+ programs(staticData_.programs)
+#endif
+{
+ // Update the default matrices to the current viewport dimensions.
+ state.getProjMatrix(projMatrix);
+
+ // Calculate a second projection matrix with the near plane clipped to 100 so as
+ // not to waste lots of depth buffer precision on very close empty space, for layer
+ // types (fill-extrusion) that use the depth buffer to emulate real-world space.
+ state.getProjMatrix(nearClippedProjMatrix, 100);
+
+ pixelsToGLUnits = {{ 2.0f / state.getSize().width, -2.0f / state.getSize().height }};
+
+ if (state.getViewportMode() == ViewportMode::FlippedY) {
+ pixelsToGLUnits[1] *= -1;
+ }
+}
+
+mat4 PaintParameters::matrixForTile(const UnwrappedTileID& tileID) {
+ mat4 matrix;
+ state.matrixFor(matrix, tileID);
+ matrix::multiply(matrix, projMatrix, matrix);
+ return matrix;
+}
+
+gl::DepthMode PaintParameters::depthModeForSublayer(uint8_t n, gl::DepthMode::Mask mask) const {
+ float nearDepth = ((1 + currentLayer) * numSublayers + n) * depthEpsilon;
+ float farDepth = nearDepth + depthRangeSize;
+ return gl::DepthMode { gl::DepthMode::LessEqual, mask, { nearDepth, farDepth } };
+}
+
+gl::DepthMode PaintParameters::depthModeFor3D(gl::DepthMode::Mask mask) const {
+ return gl::DepthMode { gl::DepthMode::LessEqual, mask, { 0.0, 1.0 } };
+}
+
+gl::StencilMode PaintParameters::stencilModeForClipping(const ClipID& id) const {
+ return gl::StencilMode {
+ gl::StencilMode::Equal { static_cast<uint32_t>(id.mask.to_ulong()) },
+ static_cast<int32_t>(id.reference.to_ulong()),
+ 0,
+ gl::StencilMode::Keep,
+ gl::StencilMode::Keep,
+ gl::StencilMode::Replace
+ };
+}
+
+gl::ColorMode PaintParameters::colorModeForRenderPass() const {
+ if (debugOptions & MapDebugOptions::Overdraw) {
+ const float overdraw = 1.0f / 8.0f;
+ return gl::ColorMode {
+ gl::ColorMode::Add {
+ gl::ColorMode::ConstantColor,
+ gl::ColorMode::One
+ },
+ Color { overdraw, overdraw, overdraw, 0.0f },
+ gl::ColorMode::Mask { true, true, true, true }
+ };
+ } else if (pass == RenderPass::Translucent) {
+ return gl::ColorMode::alphaBlended();
+ } else {
+ return gl::ColorMode::unblended();
+ }
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/paint_parameters.hpp b/src/mbgl/renderer/paint_parameters.hpp
index 213c01cfbd..4a2c2c6f12 100644
--- a/src/mbgl/renderer/paint_parameters.hpp
+++ b/src/mbgl/renderer/paint_parameters.hpp
@@ -1,14 +1,78 @@
#pragma once
+#include <mbgl/renderer/render_pass.hpp>
+#include <mbgl/renderer/render_light.hpp>
+#include <mbgl/map/mode.hpp>
+#include <mbgl/gl/depth_mode.hpp>
+#include <mbgl/gl/stencil_mode.hpp>
+#include <mbgl/gl/color_mode.hpp>
+#include <mbgl/util/mat4.hpp>
+#include <mbgl/algorithm/generate_clip_ids.hpp>
+
+#include <array>
+
namespace mbgl {
+class RendererBackend;
+class UpdateParameters;
+class RenderStaticData;
+class FrameHistory;
class Programs;
-class View;
+class TransformState;
+class ImageManager;
+class LineAtlas;
+class UnwrappedTileID;
class PaintParameters {
public:
+ PaintParameters(gl::Context&,
+ float pixelRatio,
+ GLContextMode,
+ RendererBackend&,
+ const UpdateParameters&,
+ const EvaluatedLight&,
+ RenderStaticData&,
+ FrameHistory&,
+ ImageManager&,
+ LineAtlas&);
+
+ gl::Context& context;
+ RendererBackend& backend;
+
+ const TransformState& state;
+ const EvaluatedLight& evaluatedLight;
+
+ RenderStaticData& staticData;
+ FrameHistory& frameHistory;
+ ImageManager& imageManager;
+ LineAtlas& lineAtlas;
+
+ RenderPass pass = RenderPass::Opaque;
+ MapMode mapMode;
+ MapDebugOptions debugOptions;
+ GLContextMode contextMode;
+ TimePoint timePoint;
+
+ float pixelRatio;
+ std::array<float, 2> pixelsToGLUnits;
+ algorithm::ClipIDGenerator clipIDGenerator;
+
Programs& programs;
- View& view;
+
+ gl::DepthMode depthModeForSublayer(uint8_t n, gl::DepthMode::Mask) const;
+ gl::DepthMode depthModeFor3D(gl::DepthMode::Mask) const;
+ gl::StencilMode stencilModeForClipping(const ClipID&) const;
+ gl::ColorMode colorModeForRenderPass() const;
+
+ mat4 matrixForTile(const UnwrappedTileID&);
+
+ mat4 projMatrix;
+ mat4 nearClippedProjMatrix;
+
+ int numSublayers = 3;
+ uint32_t currentLayer;
+ float depthRangeSize;
+ const float depthEpsilon = 1.0f / (1 << 16);
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/paint_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp
index 36d2e98082..652948c8df 100644
--- a/src/mbgl/renderer/paint_property_binder.hpp
+++ b/src/mbgl/renderer/paint_property_binder.hpp
@@ -5,6 +5,7 @@
#include <mbgl/gl/uniform.hpp>
#include <mbgl/gl/context.hpp>
#include <mbgl/util/type_list.hpp>
+#include <mbgl/renderer/possibly_evaluated_property_value.hpp>
#include <mbgl/renderer/paint_property_statistics.hpp>
#include <bitset>
@@ -217,7 +218,11 @@ public:
}
float interpolationFactor(float currentZoom) const override {
- return util::interpolationFactor(1.0f, { rangeOfCoveringRanges.min.zoom, rangeOfCoveringRanges.max.zoom }, currentZoom);
+ if (function.useIntegerZoom) {
+ return util::interpolationFactor(1.0f, { rangeOfCoveringRanges.min.zoom, rangeOfCoveringRanges.max.zoom }, std::floor(currentZoom));
+ } else {
+ return util::interpolationFactor(1.0f, { rangeOfCoveringRanges.min.zoom, rangeOfCoveringRanges.max.zoom }, currentZoom);
+ }
}
T uniformValue(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override {
diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp
deleted file mode 100644
index fbaf40d5c0..0000000000
--- a/src/mbgl/renderer/painter.cpp
+++ /dev/null
@@ -1,430 +0,0 @@
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/renderer/paint_parameters.hpp>
-#include <mbgl/renderer/render_tile.hpp>
-#include <mbgl/renderer/render_source.hpp>
-
-#include <mbgl/style/source.hpp>
-#include <mbgl/style/source_impl.hpp>
-
-#include <mbgl/map/view.hpp>
-
-#include <mbgl/util/logging.hpp>
-#include <mbgl/gl/debugging.hpp>
-
-#include <mbgl/style/style.hpp>
-#include <mbgl/style/layer_impl.hpp>
-
-#include <mbgl/tile/tile.hpp>
-#include <mbgl/renderer/render_background_layer.hpp>
-#include <mbgl/renderer/render_custom_layer.hpp>
-#include <mbgl/style/layers/custom_layer_impl.hpp>
-#include <mbgl/renderer/render_fill_extrusion_layer.hpp>
-
-#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/geometry/line_atlas.hpp>
-#include <mbgl/text/glyph_atlas.hpp>
-
-#include <mbgl/programs/program_parameters.hpp>
-#include <mbgl/programs/programs.hpp>
-
-#include <mbgl/algorithm/generate_clip_ids.hpp>
-#include <mbgl/algorithm/generate_clip_ids_impl.hpp>
-
-#include <mbgl/util/constants.hpp>
-#include <mbgl/util/mat3.hpp>
-#include <mbgl/util/string.hpp>
-
-#include <mbgl/util/stopwatch.hpp>
-
-#include <cassert>
-#include <algorithm>
-#include <iostream>
-#include <unordered_set>
-
-namespace mbgl {
-
-using namespace style;
-
-static gl::VertexVector<FillLayoutVertex> tileVertices() {
- gl::VertexVector<FillLayoutVertex> result;
- result.emplace_back(FillProgram::layoutVertex({ 0, 0 }));
- result.emplace_back(FillProgram::layoutVertex({ util::EXTENT, 0 }));
- result.emplace_back(FillProgram::layoutVertex({ 0, util::EXTENT }));
- result.emplace_back(FillProgram::layoutVertex({ util::EXTENT, util::EXTENT }));
- return result;
-}
-
-static gl::IndexVector<gl::Triangles> quadTriangleIndices() {
- gl::IndexVector<gl::Triangles> result;
- result.emplace_back(0, 1, 2);
- result.emplace_back(1, 2, 3);
- return result;
-}
-
-static gl::IndexVector<gl::LineStrip> tileLineStripIndices() {
- gl::IndexVector<gl::LineStrip> result;
- result.emplace_back(0);
- result.emplace_back(1);
- result.emplace_back(3);
- result.emplace_back(2);
- result.emplace_back(0);
- return result;
-}
-
-static gl::VertexVector<RasterLayoutVertex> rasterVertices() {
- gl::VertexVector<RasterLayoutVertex> result;
- result.emplace_back(RasterProgram::layoutVertex({ 0, 0 }, { 0, 0 }));
- result.emplace_back(RasterProgram::layoutVertex({ util::EXTENT, 0 }, { 32767, 0 }));
- result.emplace_back(RasterProgram::layoutVertex({ 0, util::EXTENT }, { 0, 32767 }));
- result.emplace_back(RasterProgram::layoutVertex({ util::EXTENT, util::EXTENT }, { 32767, 32767 }));
- return result;
-}
-
-static gl::VertexVector<ExtrusionTextureLayoutVertex> extrusionTextureVertices() {
- gl::VertexVector<ExtrusionTextureLayoutVertex> result;
- result.emplace_back(ExtrusionTextureProgram::layoutVertex({ 0, 0 }));
- result.emplace_back(ExtrusionTextureProgram::layoutVertex({ 1, 0 }));
- result.emplace_back(ExtrusionTextureProgram::layoutVertex({ 0, 1 }));
- result.emplace_back(ExtrusionTextureProgram::layoutVertex({ 1, 1 }));
- return result;
-}
-
-
-Painter::Painter(gl::Context& context_,
- const TransformState& state_,
- float pixelRatio,
- const optional<std::string>& programCacheDir)
- : context(context_),
- state(state_),
- tileVertexBuffer(context.createVertexBuffer(tileVertices())),
- rasterVertexBuffer(context.createVertexBuffer(rasterVertices())),
- extrusionTextureVertexBuffer(context.createVertexBuffer(extrusionTextureVertices())),
- quadTriangleIndexBuffer(context.createIndexBuffer(quadTriangleIndices())),
- tileBorderIndexBuffer(context.createIndexBuffer(tileLineStripIndices())) {
-
- tileTriangleSegments.emplace_back(0, 0, 4, 6);
- tileBorderSegments.emplace_back(0, 0, 4, 5);
- rasterSegments.emplace_back(0, 0, 4, 6);
- extrusionTextureSegments.emplace_back(0, 0, 4, 6);
-
- programs = std::make_unique<Programs>(context,
- ProgramParameters{ pixelRatio, false, programCacheDir });
-#ifndef NDEBUG
- overdrawPrograms =
- std::make_unique<Programs>(context, ProgramParameters{ pixelRatio, true, programCacheDir });
-#endif
-}
-
-Painter::~Painter() = default;
-
-bool Painter::needsAnimation() const {
- return frameHistory.needsAnimation(util::DEFAULT_FADE_DURATION);
-}
-
-void Painter::cleanup() {
- context.performCleanup();
-}
-
-void Painter::render(const Style& style, const FrameData& frame_, View& view, SpriteAtlas& annotationSpriteAtlas) {
- frame = frame_;
- if (frame.contextMode == GLContextMode::Shared) {
- context.setDirtyState();
- }
-
- PaintParameters parameters {
-#ifndef NDEBUG
- paintMode() == PaintMode::Overdraw ? *overdrawPrograms : *programs,
-#else
- *programs,
-#endif
- view
- };
-
- glyphAtlas = style.glyphAtlas.get();
- spriteAtlas = style.spriteAtlas.get();
- lineAtlas = style.lineAtlas.get();
-
- evaluatedLight = style.getRenderLight()->getEvaluated();
-
- RenderData renderData = style.getRenderData(frame.debugOptions, state.getAngle());
- const std::vector<RenderItem>& order = renderData.order;
- const std::unordered_set<RenderSource*>& sources = renderData.sources;
-
- // Update the default matrices to the current viewport dimensions.
- state.getProjMatrix(projMatrix);
- // Calculate a second projection matrix with the near plane clipped to 100 so as
- // not to waste lots of depth buffer precision on very close empty space, for layer
- // types (fill-extrusion) that use the depth buffer to emulate real-world space.
- state.getProjMatrix(nearClippedProjMatrix, 100);
-
- pixelsToGLUnits = {{ 2.0f / state.getSize().width, -2.0f / state.getSize().height }};
- if (state.getViewportMode() == ViewportMode::FlippedY) {
- pixelsToGLUnits[1] *= -1;
- }
-
- frameHistory.record(frame.timePoint, state.getZoom(),
- frame.mapMode == MapMode::Continuous ? util::DEFAULT_FADE_DURATION : Milliseconds(0));
-
-
- // - UPLOAD PASS -------------------------------------------------------------------------------
- // Uploads all required buffers and images before we do any actual rendering.
- {
- MBGL_DEBUG_GROUP(context, "upload");
-
- spriteAtlas->upload(context, 0);
-
- lineAtlas->upload(context, 0);
- glyphAtlas->upload(context, 0);
- frameHistory.upload(context, 0);
- annotationSpriteAtlas.upload(context, 0);
-
- for (const auto& item : order) {
- for (const auto& tileRef : item.tiles) {
- const auto& bucket = tileRef.get().tile.getBucket(item.layer);
- if (bucket && bucket->needsUpload()) {
- bucket->upload(context);
- }
- }
- }
- }
-
- // - CLEAR -------------------------------------------------------------------------------------
- // Renders the backdrop of the OpenGL view. This also paints in areas where we don't have any
- // tiles whatsoever.
- {
- MBGL_DEBUG_GROUP(context, "clear");
- view.bind();
- context.clear(paintMode() == PaintMode::Overdraw
- ? Color::black()
- : renderData.backgroundColor,
- 1.0f,
- 0);
- }
-
- // - CLIPPING MASKS ----------------------------------------------------------------------------
- // Draws the clipping masks to the stencil buffer.
- {
- MBGL_DEBUG_GROUP(context, "clip");
-
- // Update all clipping IDs.
- algorithm::ClipIDGenerator generator;
- for (const auto& source : sources) {
- source->startRender(generator, projMatrix, nearClippedProjMatrix, state);
- }
-
- MBGL_DEBUG_GROUP(context, "clipping masks");
-
- for (const auto& stencil : generator.getStencils()) {
- MBGL_DEBUG_GROUP(context, std::string{ "mask: " } + util::toString(stencil.first));
- renderClippingMask(stencil.first, stencil.second);
- }
- }
-
-#if not MBGL_USE_GLES2 and not defined(NDEBUG)
- if (frame.debugOptions & MapDebugOptions::StencilClip) {
- renderClipMasks(parameters);
- return;
- }
-#endif
-
- // Actually render the layers
- if (debug::renderTree) { Log::Info(Event::Render, "{"); indent++; }
-
- depthRangeSize = 1 - (order.size() + 2) * numSublayers * depthEpsilon;
-
- // - OPAQUE PASS -------------------------------------------------------------------------------
- // Render everything top-to-bottom by using reverse iterators. Render opaque objects first.
- renderPass(parameters,
- RenderPass::Opaque,
- order.rbegin(), order.rend(),
- 0, 1);
-
- // - TRANSLUCENT PASS --------------------------------------------------------------------------
- // Make a second pass, rendering translucent objects. This time, we render bottom-to-top.
- renderPass(parameters,
- RenderPass::Translucent,
- order.begin(), order.end(),
- static_cast<uint32_t>(order.size()) - 1, -1);
-
- if (debug::renderTree) { Log::Info(Event::Render, "}"); indent--; }
-
- // - DEBUG PASS --------------------------------------------------------------------------------
- // Renders debug overlays.
- {
- MBGL_DEBUG_GROUP(context, "debug");
-
- // Finalize the rendering, e.g. by calling debug render calls per tile.
- // This guarantees that we have at least one function per tile called.
- // When only rendering layers via the stylesheet, it's possible that we don't
- // ever visit a tile during rendering.
- for (const auto& source : sources) {
- source->finishRender(*this);
- }
- }
-
-#if not MBGL_USE_GLES2 and not defined(NDEBUG)
- if (frame.debugOptions & MapDebugOptions::DepthBuffer) {
- renderDepthBuffer(parameters);
- }
-#endif
-
- // TODO: Find a better way to unbind VAOs after we're done with them without introducing
- // unnecessary bind(0)/bind(N) sequences.
- {
- MBGL_DEBUG_GROUP(context, "cleanup");
-
- context.activeTexture = 1;
- context.texture[1] = 0;
- context.activeTexture = 0;
- context.texture[0] = 0;
-
- context.bindVertexArray = 0;
- }
-}
-
-template <class Iterator>
-void Painter::renderPass(PaintParameters& parameters,
- RenderPass pass_,
- Iterator it, Iterator end,
- uint32_t i, int8_t increment) {
- pass = pass_;
-
- MBGL_DEBUG_GROUP(context, pass == RenderPass::Opaque ? "opaque" : "translucent");
-
- if (debug::renderTree) {
- Log::Info(Event::Render, "%*s%s {", indent++ * 4, "",
- pass == RenderPass::Opaque ? "opaque" : "translucent");
- }
-
- for (; it != end; ++it, i += increment) {
- currentLayer = i;
-
- const auto& item = *it;
- const RenderLayer& layer = item.layer;
-
- if (!layer.hasRenderPass(pass))
- continue;
-
- if (layer.is<RenderBackgroundLayer>()) {
- MBGL_DEBUG_GROUP(context, "background");
- renderBackground(parameters, *layer.as<RenderBackgroundLayer>());
- } else if (layer.is<RenderCustomLayer>()) {
- MBGL_DEBUG_GROUP(context, layer.baseImpl.id + " - custom");
-
- // Reset GL state to a known state so the CustomLayer always has a clean slate.
- context.bindVertexArray = 0;
- context.setDepthMode(depthModeForSublayer(0, gl::DepthMode::ReadOnly));
- context.setStencilMode(gl::StencilMode::disabled());
- context.setColorMode(colorModeForRenderPass());
-
- layer.as<RenderCustomLayer>()->impl->render(state);
-
- // Reset the view back to our original one, just in case the CustomLayer changed
- // the viewport or Framebuffer.
- parameters.view.bind();
- context.setDirtyState();
- } else if (layer.is<RenderFillExtrusionLayer>()) {
- const auto size = context.viewport.getCurrentValue().size;
-
- if (!extrusionTexture || extrusionTexture->getSize() != size) {
- extrusionTexture = OffscreenTexture(context, size, OffscreenTextureAttachment::Depth);
- }
-
- extrusionTexture->bind();
-
- context.setStencilMode(gl::StencilMode::disabled());
- context.setDepthMode(depthModeForSublayer(0, gl::DepthMode::ReadWrite));
- context.clear(Color{ 0.0f, 0.0f, 0.0f, 0.0f }, 1.0f, {});
-
- for (auto& tileRef : item.tiles) {
- auto& tile = tileRef.get();
-
- MBGL_DEBUG_GROUP(context, layer.baseImpl.id + " - " + util::toString(tile.id));
- auto bucket = tile.tile.getBucket(layer);
- bucket->render(*this, parameters, layer, tile);
- }
-
- parameters.view.bind();
- context.bindTexture(extrusionTexture->getTexture());
-
- mat4 viewportMat;
- matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1);
-
- const PaintProperties<>::Evaluated properties{};
-
- parameters.programs.extrusionTexture.draw(
- context,
- gl::Triangles(),
- gl::DepthMode::disabled(),
- gl::StencilMode::disabled(),
- colorModeForRenderPass(),
- ExtrusionTextureProgram::UniformValues{
- uniforms::u_matrix::Value{ viewportMat }, uniforms::u_world::Value{ size },
- uniforms::u_image::Value{ 0 },
- uniforms::u_opacity::Value{ layer.as<RenderFillExtrusionLayer>()
- ->evaluated.get<FillExtrusionOpacity>() } },
- extrusionTextureVertexBuffer,
- quadTriangleIndexBuffer,
- extrusionTextureSegments,
- ExtrusionTextureProgram::PaintPropertyBinders{ properties, 0 },
- properties,
- state.getZoom(),
- layer.getID());
- } else {
- for (auto& tileRef : item.tiles) {
- auto& tile = tileRef.get();
- MBGL_DEBUG_GROUP(context, layer.baseImpl.id + " - " + util::toString(tile.id));
- auto bucket = tile.tile.getBucket(layer);
- bucket->render(*this, parameters, layer, tile);
- }
- }
- }
-
- if (debug::renderTree) {
- Log::Info(Event::Render, "%*s%s", --indent * 4, "", "}");
- }
-}
-
-mat4 Painter::matrixForTile(const UnwrappedTileID& tileID) {
- mat4 matrix;
- state.matrixFor(matrix, tileID);
- matrix::multiply(matrix, projMatrix, matrix);
- return matrix;
-}
-
-gl::DepthMode Painter::depthModeForSublayer(uint8_t n, gl::DepthMode::Mask mask) const {
- float nearDepth = ((1 + currentLayer) * numSublayers + n) * depthEpsilon;
- float farDepth = nearDepth + depthRangeSize;
- return gl::DepthMode { gl::DepthMode::LessEqual, mask, { nearDepth, farDepth } };
-}
-
-gl::StencilMode Painter::stencilModeForClipping(const ClipID& id) const {
- return gl::StencilMode {
- gl::StencilMode::Equal { static_cast<uint32_t>(id.mask.to_ulong()) },
- static_cast<int32_t>(id.reference.to_ulong()),
- 0,
- gl::StencilMode::Keep,
- gl::StencilMode::Keep,
- gl::StencilMode::Replace
- };
-}
-
-gl::ColorMode Painter::colorModeForRenderPass() const {
- if (paintMode() == PaintMode::Overdraw) {
- const float overdraw = 1.0f / 8.0f;
- return gl::ColorMode {
- gl::ColorMode::Add {
- gl::ColorMode::ConstantColor,
- gl::ColorMode::One
- },
- Color { overdraw, overdraw, overdraw, 0.0f },
- gl::ColorMode::Mask { true, true, true, true }
- };
- } else if (pass == RenderPass::Translucent) {
- return gl::ColorMode::alphaBlended();
- } else {
- return gl::ColorMode::unblended();
- }
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp
deleted file mode 100644
index 1919ad924e..0000000000
--- a/src/mbgl/renderer/painter.hpp
+++ /dev/null
@@ -1,186 +0,0 @@
-#pragma once
-
-#include <mbgl/map/transform_state.hpp>
-
-#include <mbgl/tile/tile_id.hpp>
-
-#include <mbgl/renderer/frame_history.hpp>
-#include <mbgl/renderer/render_item.hpp>
-#include <mbgl/renderer/bucket.hpp>
-
-#include <mbgl/gl/context.hpp>
-#include <mbgl/programs/debug_program.hpp>
-#include <mbgl/programs/program_parameters.hpp>
-#include <mbgl/programs/fill_program.hpp>
-#include <mbgl/programs/extrusion_texture_program.hpp>
-#include <mbgl/programs/raster_program.hpp>
-
-#include <mbgl/style/style.hpp>
-
-#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/constants.hpp>
-#include <mbgl/util/offscreen_texture.hpp>
-
-#include <array>
-#include <vector>
-#include <set>
-#include <map>
-
-namespace mbgl {
-
-class RenderTile;
-class SpriteAtlas;
-class View;
-class GlyphAtlas;
-class LineAtlas;
-struct FrameData;
-class Tile;
-
-class DebugBucket;
-class FillBucket;
-class FillExtrusionBucket;
-class LineBucket;
-class CircleBucket;
-class SymbolBucket;
-class RasterBucket;
-
-class RenderFillLayer;
-class RenderFillExtrusionLayer;
-class RenderLineLayer;
-class RenderCircleLayer;
-class RenderSymbolLayer;
-class RenderRasterLayer;
-class RenderBackgroundLayer;
-
-class Programs;
-class PaintParameters;
-class TilePyramid;
-
-struct ClipID;
-
-namespace style {
-class Style;
-class Source;
-} // namespace style
-
-struct FrameData {
- TimePoint timePoint;
- float pixelRatio;
- MapMode mapMode;
- GLContextMode contextMode;
- MapDebugOptions debugOptions;
-};
-
-class Painter : private util::noncopyable {
-public:
- Painter(gl::Context&, const TransformState&, float pixelRatio, const optional<std::string>& programCacheDir);
- ~Painter();
-
- void render(const style::Style&,
- const FrameData&,
- View&,
- SpriteAtlas& annotationSpriteAtlas);
-
- void cleanup();
-
- void renderClippingMask(const UnwrappedTileID&, const ClipID&);
- void renderTileDebug(const RenderTile&);
- void renderFill(PaintParameters&, FillBucket&, const RenderFillLayer&, const RenderTile&);
- void renderFillExtrusion(PaintParameters&, FillExtrusionBucket&, const RenderFillExtrusionLayer&, const RenderTile&);
- void renderLine(PaintParameters&, LineBucket&, const RenderLineLayer&, const RenderTile&);
- void renderCircle(PaintParameters&, CircleBucket&, const RenderCircleLayer&, const RenderTile&);
- void renderSymbol(PaintParameters&, SymbolBucket&, const RenderSymbolLayer&, const RenderTile&);
- void renderRaster(PaintParameters&, RasterBucket&, const RenderRasterLayer&, const RenderTile&);
- void renderBackground(PaintParameters&, const RenderBackgroundLayer&);
-
-#ifndef NDEBUG
- // Renders tile clip boundaries, using stencil buffer to calculate fill color.
- void renderClipMasks(PaintParameters&);
- // Renders the depth buffer.
- void renderDepthBuffer(PaintParameters&);
-#endif
-
- bool needsAnimation() const;
-
-private:
- std::vector<RenderItem> determineRenderOrder(const style::Style&);
-
- template <class Iterator>
- void renderPass(PaintParameters&,
- RenderPass,
- Iterator it, Iterator end,
- uint32_t i, int8_t increment);
-
- mat4 matrixForTile(const UnwrappedTileID&);
- gl::DepthMode depthModeForSublayer(uint8_t n, gl::DepthMode::Mask) const;
- gl::StencilMode stencilModeForClipping(const ClipID&) const;
- gl::ColorMode colorModeForRenderPass() const;
-
-#ifndef NDEBUG
- PaintMode paintMode() const {
- return frame.debugOptions & MapDebugOptions::Overdraw ? PaintMode::Overdraw
- : PaintMode::Regular;
- }
-#else
- PaintMode paintMode() const {
- return PaintMode::Regular;
- }
-#endif
-
-private:
- gl::Context& context;
-
- mat4 projMatrix;
- mat4 nearClippedProjMatrix;
-
- std::array<float, 2> pixelsToGLUnits;
-
- const mat4 identityMatrix = []{
- mat4 identity;
- matrix::identity(identity);
- return identity;
- }();
-
- const TransformState& state;
-
- FrameData frame;
-
- int indent = 0;
-
- RenderPass pass = RenderPass::Opaque;
-
- int numSublayers = 3;
- uint32_t currentLayer;
- float depthRangeSize;
- const float depthEpsilon = 1.0f / (1 << 16);
-
- SpriteAtlas* spriteAtlas = nullptr;
- GlyphAtlas* glyphAtlas = nullptr;
- LineAtlas* lineAtlas = nullptr;
-
- optional<OffscreenTexture> extrusionTexture;
-
- EvaluatedLight evaluatedLight;
-
- FrameHistory frameHistory;
-
- std::unique_ptr<Programs> programs;
-#ifndef NDEBUG
- std::unique_ptr<Programs> overdrawPrograms;
-#endif
-
- gl::VertexBuffer<FillLayoutVertex> tileVertexBuffer;
- gl::VertexBuffer<RasterLayoutVertex> rasterVertexBuffer;
- gl::VertexBuffer<ExtrusionTextureLayoutVertex> extrusionTextureVertexBuffer;
-
- gl::IndexBuffer<gl::Triangles> quadTriangleIndexBuffer;
- gl::IndexBuffer<gl::LineStrip> tileBorderIndexBuffer;
-
- SegmentVector<FillAttributes> tileTriangleSegments;
- SegmentVector<DebugAttributes> tileBorderSegments;
- SegmentVector<RasterAttributes> rasterSegments;
- SegmentVector<ExtrusionTextureAttributes> extrusionTextureSegments;
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/painter_background.cpp b/src/mbgl/renderer/painter_background.cpp
deleted file mode 100644
index 9bd9431082..0000000000
--- a/src/mbgl/renderer/painter_background.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/renderer/paint_parameters.hpp>
-#include <mbgl/renderer/render_background_layer.hpp>
-#include <mbgl/style/layers/background_layer_impl.hpp>
-#include <mbgl/programs/programs.hpp>
-#include <mbgl/programs/fill_program.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/util/tile_cover.hpp>
-
-namespace mbgl {
-
-using namespace style;
-
-void Painter::renderBackground(PaintParameters& parameters, const RenderBackgroundLayer& layer) {
- // Note that for bottommost layers without a pattern, the background color is drawn with
- // glClear rather than this method.
- const BackgroundPaintProperties::Evaluated& background = layer.evaluated;
-
- style::FillPaintProperties::Evaluated properties;
- properties.get<FillPattern>() = background.get<BackgroundPattern>();
- properties.get<FillOpacity>() = { background.get<BackgroundOpacity>() };
- properties.get<FillColor>() = { background.get<BackgroundColor>() };
-
- const FillProgram::PaintPropertyBinders paintAttibuteData(properties, 0);
-
- if (!background.get<BackgroundPattern>().to.empty()) {
- optional<SpriteAtlasElement> imagePosA = spriteAtlas->getPattern(background.get<BackgroundPattern>().from);
- optional<SpriteAtlasElement> imagePosB = spriteAtlas->getPattern(background.get<BackgroundPattern>().to);
-
- if (!imagePosA || !imagePosB)
- return;
-
- spriteAtlas->bind(true, context, 0);
-
- for (const auto& tileID : util::tileCover(state, state.getIntegerZoom())) {
- parameters.programs.fillPattern.get(properties).draw(
- context,
- gl::Triangles(),
- depthModeForSublayer(0, gl::DepthMode::ReadOnly),
- gl::StencilMode::disabled(),
- colorModeForRenderPass(),
- FillPatternUniforms::values(
- matrixForTile(tileID),
- context.viewport.getCurrentValue().size,
- *imagePosA,
- *imagePosB,
- background.get<BackgroundPattern>(),
- tileID,
- state
- ),
- tileVertexBuffer,
- quadTriangleIndexBuffer,
- tileTriangleSegments,
- paintAttibuteData,
- properties,
- state.getZoom(),
- layer.getID()
- );
- }
- } else {
- for (const auto& tileID : util::tileCover(state, state.getIntegerZoom())) {
- parameters.programs.fill.get(properties).draw(
- context,
- gl::Triangles(),
- depthModeForSublayer(0, gl::DepthMode::ReadOnly),
- gl::StencilMode::disabled(),
- colorModeForRenderPass(),
- FillProgram::UniformValues {
- uniforms::u_matrix::Value{ matrixForTile(tileID) },
- uniforms::u_world::Value{ context.viewport.getCurrentValue().size },
- },
- tileVertexBuffer,
- quadTriangleIndexBuffer,
- tileTriangleSegments,
- paintAttibuteData,
- properties,
- state.getZoom(),
- layer.getID()
- );
- }
- }
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/painter_circle.cpp b/src/mbgl/renderer/painter_circle.cpp
deleted file mode 100644
index ecd7598de9..0000000000
--- a/src/mbgl/renderer/painter_circle.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/renderer/paint_parameters.hpp>
-#include <mbgl/renderer/circle_bucket.hpp>
-#include <mbgl/renderer/render_tile.hpp>
-#include <mbgl/renderer/render_circle_layer.hpp>
-#include <mbgl/style/layers/circle_layer_impl.hpp>
-#include <mbgl/programs/programs.hpp>
-#include <mbgl/programs/circle_program.hpp>
-#include <mbgl/gl/context.hpp>
-
-namespace mbgl {
-
-using namespace style;
-
-void Painter::renderCircle(PaintParameters& parameters,
- CircleBucket& bucket,
- const RenderCircleLayer& layer,
- const RenderTile& tile) {
- if (pass == RenderPass::Opaque) {
- return;
- }
-
- const CirclePaintProperties::Evaluated& properties = layer.evaluated;
- const bool scaleWithMap = properties.get<CirclePitchScale>() == CirclePitchScaleType::Map;
-
- parameters.programs.circle.get(properties).draw(
- context,
- gl::Triangles(),
- depthModeForSublayer(0, gl::DepthMode::ReadOnly),
- frame.mapMode == MapMode::Still
- ? stencilModeForClipping(tile.clip)
- : gl::StencilMode::disabled(),
- colorModeForRenderPass(),
- CircleProgram::UniformValues {
- uniforms::u_matrix::Value{
- tile.translatedMatrix(properties.get<CircleTranslate>(),
- properties.get<CircleTranslateAnchor>(),
- state)
- },
- uniforms::u_scale_with_map::Value{ scaleWithMap },
- uniforms::u_extrude_scale::Value{ scaleWithMap
- ? std::array<float, 2> {{
- pixelsToGLUnits[0] * state.getCameraToCenterDistance(),
- pixelsToGLUnits[1] * state.getCameraToCenterDistance()
- }}
- : pixelsToGLUnits }
- },
- *bucket.vertexBuffer,
- *bucket.indexBuffer,
- bucket.segments,
- bucket.paintPropertyBinders.at(layer.getID()),
- properties,
- state.getZoom(),
- layer.getID()
- );
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/painter_clipping.cpp b/src/mbgl/renderer/painter_clipping.cpp
deleted file mode 100644
index 162f3b1d96..0000000000
--- a/src/mbgl/renderer/painter_clipping.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/programs/programs.hpp>
-#include <mbgl/programs/fill_program.hpp>
-#include <mbgl/util/clip_id.hpp>
-
-namespace mbgl {
-
-void Painter::renderClippingMask(const UnwrappedTileID& tileID, const ClipID& clip) {
- static const style::FillPaintProperties::Evaluated properties {};
- static const FillProgram::PaintPropertyBinders paintAttibuteData(properties, 0);
- programs->fill.get(properties).draw(
- context,
- gl::Triangles(),
- gl::DepthMode::disabled(),
- gl::StencilMode {
- gl::StencilMode::Always(),
- static_cast<int32_t>(clip.reference.to_ulong()),
- 0b11111111,
- gl::StencilMode::Keep,
- gl::StencilMode::Keep,
- gl::StencilMode::Replace
- },
- gl::ColorMode::disabled(),
- FillProgram::UniformValues {
- uniforms::u_matrix::Value{ matrixForTile(tileID) },
- uniforms::u_world::Value{ context.viewport.getCurrentValue().size },
- },
- tileVertexBuffer,
- quadTriangleIndexBuffer,
- tileTriangleSegments,
- paintAttibuteData,
- properties,
- state.getZoom(),
- "clipping"
- );
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/painter_debug.cpp b/src/mbgl/renderer/painter_debug.cpp
deleted file mode 100644
index 9a24ab5422..0000000000
--- a/src/mbgl/renderer/painter_debug.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/renderer/debug_bucket.hpp>
-#include <mbgl/renderer/render_tile.hpp>
-#include <mbgl/renderer/paint_parameters.hpp>
-#include <mbgl/map/view.hpp>
-#include <mbgl/tile/tile.hpp>
-#include <mbgl/programs/programs.hpp>
-#include <mbgl/programs/fill_program.hpp>
-#include <mbgl/util/string.hpp>
-#include <mbgl/gl/debugging.hpp>
-#include <mbgl/util/color.hpp>
-
-namespace mbgl {
-
-using namespace style;
-
-void Painter::renderTileDebug(const RenderTile& renderTile) {
- if (frame.debugOptions == MapDebugOptions::NoDebug)
- return;
-
- MBGL_DEBUG_GROUP(context, std::string { "debug " } + util::toString(renderTile.id));
-
- static const style::PaintProperties<>::Evaluated properties {};
- static const DebugProgram::PaintPropertyBinders paintAttibuteData(properties, 0);
-
- auto draw = [&] (Color color, const auto& vertexBuffer, const auto& indexBuffer, const auto& segments, auto drawMode) {
- programs->debug.draw(
- context,
- drawMode,
- gl::DepthMode::disabled(),
- stencilModeForClipping(renderTile.clip),
- gl::ColorMode::unblended(),
- DebugProgram::UniformValues {
- uniforms::u_matrix::Value{ renderTile.matrix },
- uniforms::u_color::Value{ color }
- },
- vertexBuffer,
- indexBuffer,
- segments,
- paintAttibuteData,
- properties,
- state.getZoom(),
- "debug"
- );
- };
-
- if (frame.debugOptions & (MapDebugOptions::Timestamps | MapDebugOptions::ParseStatus)) {
- Tile& tile = renderTile.tile;
- if (!tile.debugBucket || tile.debugBucket->renderable != tile.isRenderable() ||
- tile.debugBucket->complete != tile.isComplete() ||
- !(tile.debugBucket->modified == tile.modified) ||
- !(tile.debugBucket->expires == tile.expires) ||
- tile.debugBucket->debugMode != frame.debugOptions) {
- tile.debugBucket = std::make_unique<DebugBucket>(
- tile.id, tile.isRenderable(), tile.isComplete(), tile.modified,
- tile.expires, frame.debugOptions, context);
- }
-
- draw(Color::white(),
- *tile.debugBucket->vertexBuffer,
- *tile.debugBucket->indexBuffer,
- tile.debugBucket->segments,
- gl::Lines { 4.0f * frame.pixelRatio });
-
- draw(Color::black(),
- *tile.debugBucket->vertexBuffer,
- *tile.debugBucket->indexBuffer,
- tile.debugBucket->segments,
- gl::Lines { 2.0f * frame.pixelRatio });
- }
-
- if (frame.debugOptions & MapDebugOptions::TileBorders) {
- draw(Color::red(),
- tileVertexBuffer,
- tileBorderIndexBuffer,
- tileBorderSegments,
- gl::LineStrip { 4.0f * frame.pixelRatio });
- }
-}
-
-#ifndef NDEBUG
-void Painter::renderClipMasks(PaintParameters&) {
- context.setStencilMode(gl::StencilMode::disabled());
- context.setDepthMode(gl::DepthMode::disabled());
- context.setColorMode(gl::ColorMode::unblended());
- context.program = 0;
-
-#if not MBGL_USE_GLES2
- // Reset the value in case someone else changed it, or it's dirty.
- context.pixelTransferStencil = gl::value::PixelTransferStencil::Default;
-
- // Read the stencil buffer
- const auto viewport = context.viewport.getCurrentValue();
- auto image =
- context.readFramebuffer<AlphaImage, gl::TextureFormat::Stencil>(viewport.size, false);
-
- // Scale the Stencil buffer to cover the entire color space.
- auto it = image.data.get();
- auto end = it + viewport.size.width * viewport.size.height;
- const auto factor = 255.0f / *std::max_element(it, end);
- for (; it != end; ++it) {
- *it *= factor;
- }
-
- context.pixelZoom = { 1, 1 };
- context.rasterPos = { -1, -1, 0, 1 };
- context.drawPixels(image);
-#endif // MBGL_USE_GLES2
-}
-
-void Painter::renderDepthBuffer(PaintParameters&) {
- context.setStencilMode(gl::StencilMode::disabled());
- context.setDepthMode(gl::DepthMode::disabled());
- context.setColorMode(gl::ColorMode::unblended());
- context.program = 0;
-
-#if not MBGL_USE_GLES2
- // Scales the values in the depth buffer so that they cover the entire grayscale range. This
- // makes it easier to spot tiny differences.
- const float base = 1.0f / (1.0f - depthRangeSize);
- context.pixelTransferDepth = { base, 1.0f - base };
-
- // Read the stencil buffer
- auto viewport = context.viewport.getCurrentValue();
- auto image =
- context.readFramebuffer<AlphaImage, gl::TextureFormat::Depth>(viewport.size, false);
-
- context.pixelZoom = { 1, 1 };
- context.rasterPos = { -1, -1, 0, 1 };
- context.drawPixels(image);
-#endif // MBGL_USE_GLES2
-}
-#endif // NDEBUG
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painter_fill.cpp
deleted file mode 100644
index 7264735692..0000000000
--- a/src/mbgl/renderer/painter_fill.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/renderer/paint_parameters.hpp>
-#include <mbgl/renderer/fill_bucket.hpp>
-#include <mbgl/renderer/render_tile.hpp>
-#include <mbgl/renderer/render_fill_layer.hpp>
-#include <mbgl/style/layers/fill_layer_impl.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/programs/programs.hpp>
-#include <mbgl/programs/fill_program.hpp>
-#include <mbgl/util/convert.hpp>
-
-namespace mbgl {
-
-using namespace style;
-
-void Painter::renderFill(PaintParameters& parameters,
- FillBucket& bucket,
- const RenderFillLayer& layer,
- const RenderTile& tile) {
- const FillPaintProperties::Evaluated& properties = layer.evaluated;
-
- if (!properties.get<FillPattern>().from.empty()) {
- if (pass != RenderPass::Translucent) {
- return;
- }
-
- optional<SpriteAtlasElement> imagePosA = spriteAtlas->getPattern(properties.get<FillPattern>().from);
- optional<SpriteAtlasElement> imagePosB = spriteAtlas->getPattern(properties.get<FillPattern>().to);
-
- if (!imagePosA || !imagePosB) {
- return;
- }
-
- spriteAtlas->bind(true, context, 0);
-
- auto draw = [&] (uint8_t sublayer,
- auto& program,
- const auto& drawMode,
- const auto& indexBuffer,
- const auto& segments) {
- program.get(properties).draw(
- context,
- drawMode,
- depthModeForSublayer(sublayer, gl::DepthMode::ReadWrite),
- stencilModeForClipping(tile.clip),
- colorModeForRenderPass(),
- FillPatternUniforms::values(
- tile.translatedMatrix(properties.get<FillTranslate>(),
- properties.get<FillTranslateAnchor>(),
- state),
- context.viewport.getCurrentValue().size,
- *imagePosA,
- *imagePosB,
- properties.get<FillPattern>(),
- tile.id,
- state
- ),
- *bucket.vertexBuffer,
- indexBuffer,
- segments,
- bucket.paintPropertyBinders.at(layer.getID()),
- properties,
- state.getZoom(),
- layer.getID()
- );
- };
-
- draw(0,
- parameters.programs.fillPattern,
- gl::Triangles(),
- *bucket.triangleIndexBuffer,
- bucket.triangleSegments);
-
- if (!properties.get<FillAntialias>() || !layer.unevaluated.get<FillOutlineColor>().isUndefined()) {
- return;
- }
-
- draw(2,
- parameters.programs.fillOutlinePattern,
- gl::Lines { 2.0f },
- *bucket.lineIndexBuffer,
- bucket.lineSegments);
- } else {
- auto draw = [&] (uint8_t sublayer,
- auto& program,
- const auto& drawMode,
- const auto& indexBuffer,
- const auto& segments) {
- program.get(properties).draw(
- context,
- drawMode,
- depthModeForSublayer(sublayer, pass == RenderPass::Opaque
- ? gl::DepthMode::ReadWrite
- : gl::DepthMode::ReadOnly),
- stencilModeForClipping(tile.clip),
- colorModeForRenderPass(),
- FillProgram::UniformValues {
- uniforms::u_matrix::Value{
- tile.translatedMatrix(properties.get<FillTranslate>(),
- properties.get<FillTranslateAnchor>(),
- state)
- },
- uniforms::u_world::Value{ context.viewport.getCurrentValue().size },
- },
- *bucket.vertexBuffer,
- indexBuffer,
- segments,
- bucket.paintPropertyBinders.at(layer.getID()),
- properties,
- state.getZoom(),
- layer.getID()
- );
- };
-
- if (properties.get<FillAntialias>() && !layer.unevaluated.get<FillOutlineColor>().isUndefined() && pass == RenderPass::Translucent) {
- draw(2,
- parameters.programs.fillOutline,
- gl::Lines { 2.0f },
- *bucket.lineIndexBuffer,
- bucket.lineSegments);
- }
-
- // Only draw the fill when it's opaque and we're drawing opaque fragments,
- // or when it's translucent and we're drawing translucent fragments.
- if ((properties.get<FillColor>().constantOr(Color()).a >= 1.0f
- && properties.get<FillOpacity>().constantOr(0) >= 1.0f) == (pass == RenderPass::Opaque)) {
- draw(1,
- parameters.programs.fill,
- gl::Triangles(),
- *bucket.triangleIndexBuffer,
- bucket.triangleSegments);
- }
-
- if (properties.get<FillAntialias>() && layer.unevaluated.get<FillOutlineColor>().isUndefined() && pass == RenderPass::Translucent) {
- draw(2,
- parameters.programs.fillOutline,
- gl::Lines { 2.0f },
- *bucket.lineIndexBuffer,
- bucket.lineSegments);
- }
- }
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/painter_fill_extrusion.cpp b/src/mbgl/renderer/painter_fill_extrusion.cpp
deleted file mode 100644
index 5581cfe983..0000000000
--- a/src/mbgl/renderer/painter_fill_extrusion.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/renderer/paint_parameters.hpp>
-#include <mbgl/renderer/fill_extrusion_bucket.hpp>
-#include <mbgl/renderer/render_tile.hpp>
-#include <mbgl/renderer/render_fill_extrusion_layer.hpp>
-#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/programs/programs.hpp>
-#include <mbgl/programs/fill_extrusion_program.hpp>
-#include <mbgl/util/constants.hpp>
-#include <mbgl/util/convert.hpp>
-
-namespace mbgl {
-
-using namespace style;
-
-void Painter::renderFillExtrusion(PaintParameters& parameters,
- FillExtrusionBucket& bucket,
- const RenderFillExtrusionLayer& layer,
- const RenderTile& tile) {
- const FillExtrusionPaintProperties::Evaluated& properties = layer.evaluated;
-
- if (pass == RenderPass::Opaque) {
- return;
- }
-
- if (!properties.get<FillExtrusionPattern>().from.empty()) {
- optional<SpriteAtlasElement> imagePosA =
- spriteAtlas->getPattern(properties.get<FillExtrusionPattern>().from);
- optional<SpriteAtlasElement> imagePosB =
- spriteAtlas->getPattern(properties.get<FillExtrusionPattern>().to);
-
- if (!imagePosA || !imagePosB) {
- return;
- }
-
- spriteAtlas->bind(true, context, 0);
-
- parameters.programs.fillExtrusionPattern.get(properties).draw(
- context,
- gl::Triangles(),
- depthModeForSublayer(0, gl::DepthMode::ReadWrite),
- gl::StencilMode::disabled(),
- colorModeForRenderPass(),
- FillExtrusionPatternUniforms::values(
- tile.translatedClipMatrix(properties.get<FillExtrusionTranslate>(),
- properties.get<FillExtrusionTranslateAnchor>(),
- state),
- *imagePosA,
- *imagePosB,
- properties.get<FillExtrusionPattern>(),
- tile.id,
- state,
- -std::pow(2, tile.id.canonical.z) / util::tileSize / 8.0f,
- evaluatedLight
- ),
- *bucket.vertexBuffer,
- *bucket.indexBuffer,
- bucket.triangleSegments,
- bucket.paintPropertyBinders.at(layer.getID()),
- properties,
- state.getZoom(),
- layer.getID());
-
- } else {
- parameters.programs.fillExtrusion.get(properties).draw(
- context,
- gl::Triangles(),
- depthModeForSublayer(0, gl::DepthMode::ReadWrite),
- gl::StencilMode::disabled(),
- colorModeForRenderPass(),
- FillExtrusionUniforms::values(
- tile.translatedClipMatrix(properties.get<FillExtrusionTranslate>(),
- properties.get<FillExtrusionTranslateAnchor>(),
- state),
- state,
- evaluatedLight
- ),
- *bucket.vertexBuffer,
- *bucket.indexBuffer,
- bucket.triangleSegments,
- bucket.paintPropertyBinders.at(layer.getID()),
- properties,
- state.getZoom(),
- layer.getID());
- };
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/painter_line.cpp b/src/mbgl/renderer/painter_line.cpp
deleted file mode 100644
index 209b1447d0..0000000000
--- a/src/mbgl/renderer/painter_line.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/renderer/paint_parameters.hpp>
-#include <mbgl/renderer/line_bucket.hpp>
-#include <mbgl/renderer/render_tile.hpp>
-#include <mbgl/renderer/render_line_layer.hpp>
-#include <mbgl/style/layers/line_layer_impl.hpp>
-#include <mbgl/programs/programs.hpp>
-#include <mbgl/programs/line_program.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/geometry/line_atlas.hpp>
-
-namespace mbgl {
-
-using namespace style;
-
-void Painter::renderLine(PaintParameters& parameters,
- LineBucket& bucket,
- const RenderLineLayer& layer,
- const RenderTile& tile) {
- if (pass == RenderPass::Opaque) {
- return;
- }
-
- const LinePaintProperties::Evaluated& properties = layer.evaluated;
-
- auto draw = [&] (auto& program, auto&& uniformValues) {
- program.get(properties).draw(
- context,
- gl::Triangles(),
- depthModeForSublayer(0, gl::DepthMode::ReadOnly),
- stencilModeForClipping(tile.clip),
- colorModeForRenderPass(),
- std::move(uniformValues),
- *bucket.vertexBuffer,
- *bucket.indexBuffer,
- bucket.segments,
- bucket.paintPropertyBinders.at(layer.getID()),
- properties,
- state.getZoom(),
- layer.getID()
- );
- };
-
- if (!properties.get<LineDasharray>().from.empty()) {
- const LinePatternCap cap = bucket.layout.get<LineCap>() == LineCapType::Round
- ? LinePatternCap::Round : LinePatternCap::Square;
- LinePatternPos posA = lineAtlas->getDashPosition(properties.get<LineDasharray>().from, cap);
- LinePatternPos posB = lineAtlas->getDashPosition(properties.get<LineDasharray>().to, cap);
-
- lineAtlas->bind(context, 0);
-
- draw(parameters.programs.lineSDF,
- LineSDFProgram::uniformValues(
- properties,
- frame.pixelRatio,
- tile,
- state,
- pixelsToGLUnits,
- posA,
- posB,
- layer.dashLineWidth,
- lineAtlas->getSize().width));
-
- } else if (!properties.get<LinePattern>().from.empty()) {
- optional<SpriteAtlasElement> posA = spriteAtlas->getPattern(properties.get<LinePattern>().from);
- optional<SpriteAtlasElement> posB = spriteAtlas->getPattern(properties.get<LinePattern>().to);
-
- if (!posA || !posB)
- return;
-
- spriteAtlas->bind(true, context, 0);
-
- draw(parameters.programs.linePattern,
- LinePatternProgram::uniformValues(
- properties,
- tile,
- state,
- pixelsToGLUnits,
- *posA,
- *posB));
-
- } else {
- draw(parameters.programs.line,
- LineProgram::uniformValues(
- properties,
- tile,
- state,
- pixelsToGLUnits));
- }
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/painter_raster.cpp b/src/mbgl/renderer/painter_raster.cpp
deleted file mode 100644
index f0e5399f4a..0000000000
--- a/src/mbgl/renderer/painter_raster.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/renderer/paint_parameters.hpp>
-#include <mbgl/renderer/render_tile.hpp>
-#include <mbgl/renderer/raster_bucket.hpp>
-#include <mbgl/renderer/render_raster_layer.hpp>
-#include <mbgl/style/layers/raster_layer_impl.hpp>
-#include <mbgl/programs/programs.hpp>
-#include <mbgl/programs/raster_program.hpp>
-
-namespace mbgl {
-
-using namespace style;
-
-static float saturationFactor(float saturation) {
- if (saturation > 0) {
- return 1 - 1 / (1.001 - saturation);
- } else {
- return -saturation;
- }
-}
-
-static float contrastFactor(float contrast) {
- if (contrast > 0) {
- return 1 / (1 - contrast);
- } else {
- return 1 + contrast;
- }
-}
-
-static std::array<float, 3> spinWeights(float spin) {
- spin *= util::DEG2RAD;
- float s = std::sin(spin);
- float c = std::cos(spin);
- std::array<float, 3> spin_weights = {{
- (2 * c + 1) / 3,
- (-std::sqrt(3.0f) * s - c + 1) / 3,
- (std::sqrt(3.0f) * s - c + 1) / 3
- }};
- return spin_weights;
-}
-
-void Painter::renderRaster(PaintParameters& parameters,
- RasterBucket& bucket,
- const RenderRasterLayer& layer,
- const RenderTile& tile) {
- if (pass != RenderPass::Translucent)
- return;
- if (!bucket.hasData())
- return;
-
- const RasterPaintProperties::Evaluated& properties = layer.evaluated;
- const RasterProgram::PaintPropertyBinders paintAttributeData(properties, 0);
-
- assert(bucket.texture);
- context.bindTexture(*bucket.texture, 0, gl::TextureFilter::Linear);
- context.bindTexture(*bucket.texture, 1, gl::TextureFilter::Linear);
-
- parameters.programs.raster.draw(
- context,
- gl::Triangles(),
- depthModeForSublayer(0, gl::DepthMode::ReadOnly),
- gl::StencilMode::disabled(),
- colorModeForRenderPass(),
- RasterProgram::UniformValues {
- uniforms::u_matrix::Value{ tile.matrix },
- uniforms::u_image0::Value{ 0 },
- uniforms::u_image1::Value{ 1 },
- uniforms::u_opacity::Value{ properties.get<RasterOpacity>() },
- uniforms::u_fade_t::Value{ 1 },
- uniforms::u_brightness_low::Value{ properties.get<RasterBrightnessMin>() },
- uniforms::u_brightness_high::Value{ properties.get<RasterBrightnessMax>() },
- uniforms::u_saturation_factor::Value{ saturationFactor(properties.get<RasterSaturation>()) },
- uniforms::u_contrast_factor::Value{ contrastFactor(properties.get<RasterContrast>()) },
- uniforms::u_spin_weights::Value{ spinWeights(properties.get<RasterHueRotate>()) },
- uniforms::u_buffer_scale::Value{ 1.0f },
- uniforms::u_scale_parent::Value{ 1.0f },
- uniforms::u_tl_parent::Value{ std::array<float, 2> {{ 0.0f, 0.0f }} },
- },
- rasterVertexBuffer,
- quadTriangleIndexBuffer,
- rasterSegments,
- paintAttributeData,
- properties,
- state.getZoom(),
- layer.getID()
- );
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp
deleted file mode 100644
index 6462eebdcc..0000000000
--- a/src/mbgl/renderer/painter_symbol.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/renderer/paint_parameters.hpp>
-#include <mbgl/renderer/symbol_bucket.hpp>
-#include <mbgl/renderer/render_tile.hpp>
-#include <mbgl/renderer/render_symbol_layer.hpp>
-#include <mbgl/style/layers/symbol_layer_impl.hpp>
-#include <mbgl/text/glyph_atlas.hpp>
-#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/programs/programs.hpp>
-#include <mbgl/programs/symbol_program.hpp>
-#include <mbgl/programs/collision_box_program.hpp>
-#include <mbgl/util/math.hpp>
-#include <mbgl/tile/tile.hpp>
-
-#include <cmath>
-
-namespace mbgl {
-
-using namespace style;
-
-void Painter::renderSymbol(PaintParameters& parameters,
- SymbolBucket& bucket,
- const RenderSymbolLayer& layer,
- const RenderTile& tile) {
- if (pass == RenderPass::Opaque) {
- return;
- }
-
- const auto& layout = bucket.layout;
-
- frameHistory.bind(context, 1);
-
- auto draw = [&] (auto& program,
- auto&& uniformValues,
- const auto& buffers,
- const auto& symbolSizeBinder,
- const SymbolPropertyValues& values_,
- const auto& binders,
- const auto& paintProperties)
- {
- // We clip symbols to their tile extent in still mode.
- const bool needsClipping = frame.mapMode == MapMode::Still;
-
- program.get(paintProperties).draw(
- context,
- gl::Triangles(),
- values_.pitchAlignment == AlignmentType::Map
- ? depthModeForSublayer(0, gl::DepthMode::ReadOnly)
- : gl::DepthMode::disabled(),
- needsClipping
- ? stencilModeForClipping(tile.clip)
- : gl::StencilMode::disabled(),
- colorModeForRenderPass(),
- std::move(uniformValues),
- *buffers.vertexBuffer,
- *symbolSizeBinder,
- *buffers.indexBuffer,
- buffers.segments,
- binders,
- paintProperties,
- state.getZoom(),
- layer.getID()
- );
- };
-
- if (bucket.hasIconData()) {
- auto values = layer.iconPropertyValues(layout);
- auto paintPropertyValues = layer.iconPaintProperties();
-
- SpriteAtlas& atlas = *bucket.spriteAtlas;
- const bool iconScaled = layout.get<IconSize>().constantOr(1.0) != 1.0 ||
- frame.pixelRatio != atlas.getPixelRatio() ||
- bucket.iconsNeedLinear;
- const bool iconTransformed = values.rotationAlignment == AlignmentType::Map || state.getPitch() != 0;
- atlas.bind(bucket.sdfIcons || state.isChanging() || iconScaled || iconTransformed, context, 0);
-
- const Size texsize = atlas.getSize();
-
- if (bucket.sdfIcons) {
- if (values.hasHalo) {
- draw(parameters.programs.symbolIconSDF,
- SymbolSDFIconProgram::uniformValues(false, values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo),
- bucket.icon,
- bucket.iconSizeBinder,
- values,
- bucket.paintPropertyBinders.at(layer.getID()).first,
- paintPropertyValues);
- }
-
- if (values.hasFill) {
- draw(parameters.programs.symbolIconSDF,
- SymbolSDFIconProgram::uniformValues(false, values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill),
- bucket.icon,
- bucket.iconSizeBinder,
- values,
- bucket.paintPropertyBinders.at(layer.getID()).first,
- paintPropertyValues);
- }
- } else {
- draw(parameters.programs.symbolIcon,
- SymbolIconProgram::uniformValues(false, values, texsize, pixelsToGLUnits, tile, state),
- bucket.icon,
- bucket.iconSizeBinder,
- values,
- bucket.paintPropertyBinders.at(layer.getID()).first,
- paintPropertyValues);
- }
- }
-
- if (bucket.hasTextData()) {
- glyphAtlas->bind(context, 0);
-
- auto values = layer.textPropertyValues(layout);
- auto paintPropertyValues = layer.textPaintProperties();
-
- const Size texsize = glyphAtlas->getSize();
-
- if (values.hasHalo) {
- draw(parameters.programs.symbolGlyph,
- SymbolSDFTextProgram::uniformValues(true, values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo),
- bucket.text,
- bucket.textSizeBinder,
- values,
- bucket.paintPropertyBinders.at(layer.getID()).second,
- paintPropertyValues);
- }
-
- if (values.hasFill) {
- draw(parameters.programs.symbolGlyph,
- SymbolSDFTextProgram::uniformValues(true, values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill),
- bucket.text,
- bucket.textSizeBinder,
- values,
- bucket.paintPropertyBinders.at(layer.getID()).second,
- paintPropertyValues);
- }
- }
-
- if (bucket.hasCollisionBoxData()) {
- static const style::PaintProperties<>::Evaluated properties {};
- static const CollisionBoxProgram::PaintPropertyBinders paintAttributeData(properties, 0);
-
- programs->collisionBox.draw(
- context,
- gl::Lines { 1.0f },
- gl::DepthMode::disabled(),
- gl::StencilMode::disabled(),
- colorModeForRenderPass(),
- CollisionBoxProgram::UniformValues {
- uniforms::u_matrix::Value{ tile.matrix },
- uniforms::u_scale::Value{ std::pow(2.0f, float(state.getZoom() - tile.tile.id.overscaledZ)) },
- uniforms::u_zoom::Value{ float(state.getZoom() * 10) },
- uniforms::u_maxzoom::Value{ float((tile.id.canonical.z + 1) * 10) },
- },
- *bucket.collisionBox.vertexBuffer,
- *bucket.collisionBox.indexBuffer,
- bucket.collisionBox.segments,
- paintAttributeData,
- properties,
- state.getZoom(),
- layer.getID()
- );
- }
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/possibly_evaluated_property_value.hpp b/src/mbgl/renderer/possibly_evaluated_property_value.hpp
index a0bcec2bf1..e662d5dfb1 100644
--- a/src/mbgl/renderer/possibly_evaluated_property_value.hpp
+++ b/src/mbgl/renderer/possibly_evaluated_property_value.hpp
@@ -19,7 +19,9 @@ private:
public:
PossiblyEvaluatedPropertyValue() = default;
- PossiblyEvaluatedPropertyValue(Value v) : value(std::move(v)) {}
+ PossiblyEvaluatedPropertyValue(Value v, bool useIntegerZoom_ = false)
+ : value(std::move(v)),
+ useIntegerZoom(useIntegerZoom_) {}
bool isConstant() const {
return value.template is<T>();
@@ -43,15 +45,21 @@ public:
template <class Feature>
T evaluate(const Feature& feature, float zoom, T defaultValue) const {
return this->match(
- [&] (const T& constant) { return constant; },
+ [&] (const T& constant_) { return constant_; },
[&] (const style::SourceFunction<T>& function) {
return function.evaluate(feature, defaultValue);
},
[&] (const style::CompositeFunction<T>& function) {
- return function.evaluate(zoom, feature, defaultValue);
+ if (useIntegerZoom) {
+ return function.evaluate(floor(zoom), feature, defaultValue);
+ } else {
+ return function.evaluate(zoom, feature, defaultValue);
+ }
}
);
}
+
+ bool useIntegerZoom;
};
namespace util {
diff --git a/src/mbgl/renderer/property_evaluation_parameters.hpp b/src/mbgl/renderer/property_evaluation_parameters.hpp
index 39b663bdb9..da6a4a0892 100644
--- a/src/mbgl/renderer/property_evaluation_parameters.hpp
+++ b/src/mbgl/renderer/property_evaluation_parameters.hpp
@@ -11,20 +11,24 @@ public:
: z(z_),
now(Clock::time_point::max()),
zoomHistory(),
- defaultFadeDuration(0) {}
+ defaultFadeDuration(0),
+ useIntegerZoom(false) {}
PropertyEvaluationParameters(ZoomHistory zoomHistory_,
TimePoint now_,
- Duration defaultFadeDuration_)
+ Duration defaultFadeDuration_,
+ bool useIntegerZoom_ = false)
: z(zoomHistory_.lastZoom),
now(std::move(now_)),
zoomHistory(std::move(zoomHistory_)),
- defaultFadeDuration(std::move(defaultFadeDuration_)) {}
+ defaultFadeDuration(std::move(defaultFadeDuration_)),
+ useIntegerZoom(useIntegerZoom_) {}
float z;
TimePoint now;
ZoomHistory zoomHistory;
Duration defaultFadeDuration;
+ bool useIntegerZoom;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/raster_bucket.cpp b/src/mbgl/renderer/raster_bucket.cpp
deleted file mode 100644
index ee8ef24071..0000000000
--- a/src/mbgl/renderer/raster_bucket.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#include <mbgl/renderer/raster_bucket.hpp>
-#include <mbgl/renderer/render_raster_layer.hpp>
-#include <mbgl/programs/raster_program.hpp>
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/gl/context.hpp>
-
-namespace mbgl {
-
-using namespace style;
-
-RasterBucket::RasterBucket(UnassociatedImage&& image_) : image(std::move(image_)) {
-}
-
-void RasterBucket::upload(gl::Context& context) {
- texture = context.createTexture(std::move(image));
- uploaded = true;
-}
-
-void RasterBucket::render(Painter& painter,
- PaintParameters& parameters,
- const RenderLayer& layer,
- const RenderTile& tile) {
- painter.renderRaster(parameters, *this, *layer.as<RenderRasterLayer>(), tile);
-}
-
-bool RasterBucket::hasData() const {
- return true;
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/raster_bucket.hpp b/src/mbgl/renderer/raster_bucket.hpp
deleted file mode 100644
index 334954e3f4..0000000000
--- a/src/mbgl/renderer/raster_bucket.hpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#pragma once
-
-#include <mbgl/renderer/bucket.hpp>
-#include <mbgl/util/image.hpp>
-#include <mbgl/util/optional.hpp>
-#include <mbgl/gl/texture.hpp>
-
-namespace mbgl {
-
-class RasterBucket : public Bucket {
-public:
- RasterBucket(UnassociatedImage&&);
-
- void upload(gl::Context&) override;
- void render(Painter&, PaintParameters&, const RenderLayer&, const RenderTile&) override;
- bool hasData() const override;
-
- UnassociatedImage image;
- optional<gl::Texture> texture;
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/render_background_layer.cpp b/src/mbgl/renderer/render_background_layer.cpp
deleted file mode 100644
index 485d4b16c6..0000000000
--- a/src/mbgl/renderer/render_background_layer.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-#include <mbgl/renderer/render_background_layer.hpp>
-#include <mbgl/style/layers/background_layer_impl.hpp>
-#include <mbgl/renderer/bucket.hpp>
-
-namespace mbgl {
-
-RenderBackgroundLayer::RenderBackgroundLayer(const style::BackgroundLayer::Impl& _impl)
- : RenderLayer(style::LayerType::Background, _impl),
- impl(&_impl) {
-}
-
-std::unique_ptr<RenderLayer> RenderBackgroundLayer::clone() const {
- return std::make_unique<RenderBackgroundLayer>(*this);
-}
-
-std::unique_ptr<Bucket> RenderBackgroundLayer::createBucket(const BucketParameters &,
- const std::vector<const RenderLayer *> &) const {
- assert(false);
- return nullptr;
-}
-
-void RenderBackgroundLayer::cascade(const CascadeParameters &parameters) {
- unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated));
-}
-
-void RenderBackgroundLayer::evaluate(const PropertyEvaluationParameters &parameters) {
- evaluated = unevaluated.evaluate(parameters);
-
- passes = evaluated.get<style::BackgroundOpacity>() > 0 ? RenderPass::Translucent
- : RenderPass::None;
-}
-
-bool RenderBackgroundLayer::hasTransition() const {
- return unevaluated.hasTransition();
-}
-
-}
diff --git a/src/mbgl/renderer/render_circle_layer.cpp b/src/mbgl/renderer/render_circle_layer.cpp
deleted file mode 100644
index f59c174dd3..0000000000
--- a/src/mbgl/renderer/render_circle_layer.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-#include <mbgl/renderer/render_circle_layer.hpp>
-#include <mbgl/renderer/circle_bucket.hpp>
-#include <mbgl/style/layers/circle_layer_impl.hpp>
-#include <mbgl/geometry/feature_index.hpp>
-#include <mbgl/util/math.hpp>
-#include <mbgl/util/intersection_tests.hpp>
-
-namespace mbgl {
-
-RenderCircleLayer::RenderCircleLayer(const style::CircleLayer::Impl& _impl)
- : RenderLayer(style::LayerType::Circle, _impl),
- impl(&_impl) {
-}
-
-std::unique_ptr<RenderLayer> RenderCircleLayer::clone() const {
- return std::make_unique<RenderCircleLayer>(*this);
-}
-
-std::unique_ptr<Bucket> RenderCircleLayer::createBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) const {
- return std::make_unique<CircleBucket>(parameters, layers);
-}
-
-void RenderCircleLayer::cascade(const CascadeParameters& parameters) {
- unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated));
-}
-
-void RenderCircleLayer::evaluate(const PropertyEvaluationParameters& parameters) {
- evaluated = unevaluated.evaluate(parameters);
-
- passes = ((evaluated.get<style::CircleRadius>().constantOr(1) > 0 ||
- evaluated.get<style::CircleStrokeWidth>().constantOr(1) > 0)
- && (evaluated.get<style::CircleColor>().constantOr(Color::black()).a > 0 ||
- evaluated.get<style::CircleStrokeColor>().constantOr(Color::black()).a > 0)
- && (evaluated.get<style::CircleOpacity>().constantOr(1) > 0 ||
- evaluated.get<style::CircleStrokeOpacity>().constantOr(1) > 0))
- ? RenderPass::Translucent : RenderPass::None;
-}
-
-bool RenderCircleLayer::hasTransition() const {
- return unevaluated.hasTransition();
-}
-
-bool RenderCircleLayer::queryIntersectsFeature(
- const GeometryCoordinates& queryGeometry,
- const GeometryTileFeature& feature,
- const float zoom,
- const float bearing,
- const float pixelsToTileUnits) const {
-
- // Translate query geometry
- auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
- queryGeometry,
- evaluated.get<style::CircleTranslate>(),
- evaluated.get<style::CircleTranslateAnchor>(),
- bearing,
- pixelsToTileUnits);
-
- // Evaluate function
- auto circleRadius = evaluated.get<style::CircleRadius>()
- .evaluate(feature, zoom, style::CircleRadius::defaultValue())
- * pixelsToTileUnits;
-
- // Test intersection
- return util::polygonIntersectsBufferedMultiPoint(translatedQueryGeometry.value_or(queryGeometry), feature.getGeometries(), circleRadius);
-}
-
-}
diff --git a/src/mbgl/renderer/render_custom_layer.cpp b/src/mbgl/renderer/render_custom_layer.cpp
deleted file mode 100644
index 66dd57b3d3..0000000000
--- a/src/mbgl/renderer/render_custom_layer.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-#include <mbgl/renderer/render_custom_layer.hpp>
-#include <mbgl/style/layers/custom_layer_impl.hpp>
-#include <mbgl/renderer/bucket.hpp>
-
-namespace mbgl {
-
-RenderCustomLayer::RenderCustomLayer(const style::CustomLayer::Impl& _impl)
- : RenderLayer(style::LayerType::Custom, _impl),
- impl(&_impl) {
-}
-
-std::unique_ptr<RenderLayer> RenderCustomLayer::clone() const {
- return std::make_unique<RenderCustomLayer>(*this);
-}
-
-void RenderCustomLayer::evaluate(const PropertyEvaluationParameters&) {
- passes = RenderPass::Translucent;
-}
-
-bool RenderCustomLayer::hasTransition() const {
- return false;
-}
-
-std::unique_ptr<Bucket> RenderCustomLayer::createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const {
- assert(false);
- return nullptr;
-}
-
-}
diff --git a/src/mbgl/renderer/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/render_fill_extrusion_layer.cpp
deleted file mode 100644
index f6ba164d8c..0000000000
--- a/src/mbgl/renderer/render_fill_extrusion_layer.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-#include <mbgl/renderer/render_fill_extrusion_layer.hpp>
-#include <mbgl/renderer/fill_extrusion_bucket.hpp>
-#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp>
-#include <mbgl/geometry/feature_index.hpp>
-#include <mbgl/util/math.hpp>
-#include <mbgl/util/intersection_tests.hpp>
-
-namespace mbgl {
-
-RenderFillExtrusionLayer::RenderFillExtrusionLayer(const style::FillExtrusionLayer::Impl& _impl)
- : RenderLayer(style::LayerType::FillExtrusion, _impl),
- impl(&_impl) {
-}
-
-std::unique_ptr<RenderLayer> RenderFillExtrusionLayer::clone() const {
- return std::make_unique<RenderFillExtrusionLayer>(*this);
-}
-
-std::unique_ptr<Bucket> RenderFillExtrusionLayer::createBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) const {
- return std::make_unique<FillExtrusionBucket>(parameters, layers);
-}
-
-void RenderFillExtrusionLayer::cascade(const CascadeParameters& parameters) {
- unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated));
-}
-
-void RenderFillExtrusionLayer::evaluate(const PropertyEvaluationParameters& parameters) {
- evaluated = unevaluated.evaluate(parameters);
-
- passes = (evaluated.get<style::FillExtrusionOpacity>() > 0) ? RenderPass::Translucent
- : RenderPass::None;
-}
-
-bool RenderFillExtrusionLayer::hasTransition() const {
- return unevaluated.hasTransition();
-}
-
-bool RenderFillExtrusionLayer::queryIntersectsFeature(
- const GeometryCoordinates& queryGeometry,
- const GeometryTileFeature& feature,
- const float,
- const float bearing,
- const float pixelsToTileUnits) const {
-
- auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
- queryGeometry,
- evaluated.get<style::FillExtrusionTranslate>(),
- evaluated.get<style::FillExtrusionTranslateAnchor>(),
- bearing,
- pixelsToTileUnits);
-
- return util::polygonIntersectsMultiPolygon(translatedQueryGeometry.value_or(queryGeometry), feature.getGeometries());
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/render_fill_layer.cpp b/src/mbgl/renderer/render_fill_layer.cpp
deleted file mode 100644
index 1af139cded..0000000000
--- a/src/mbgl/renderer/render_fill_layer.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-#include <mbgl/renderer/render_fill_layer.hpp>
-#include <mbgl/renderer/fill_bucket.hpp>
-#include <mbgl/style/layers/fill_layer_impl.hpp>
-#include <mbgl/geometry/feature_index.hpp>
-#include <mbgl/util/math.hpp>
-#include <mbgl/util/intersection_tests.hpp>
-
-namespace mbgl {
-
-RenderFillLayer::RenderFillLayer(const style::FillLayer::Impl& _impl)
- : RenderLayer(style::LayerType::Fill, _impl),
- impl(&_impl) {
-}
-
-std::unique_ptr<RenderLayer> RenderFillLayer::clone() const {
- return std::make_unique<RenderFillLayer>(*this);
-}
-
-std::unique_ptr<Bucket> RenderFillLayer::createBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) const {
- return std::make_unique<FillBucket>(parameters, layers);
-}
-
-void RenderFillLayer::cascade(const CascadeParameters& parameters) {
- unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated));
-}
-
-void RenderFillLayer::evaluate(const PropertyEvaluationParameters& parameters) {
- evaluated = unevaluated.evaluate(parameters);
-
- if (unevaluated.get<style::FillOutlineColor>().isUndefined()) {
- evaluated.get<style::FillOutlineColor>() = evaluated.get<style::FillColor>();
- }
-
- passes = RenderPass::None;
-
- if (evaluated.get<style::FillAntialias>()) {
- passes |= RenderPass::Translucent;
- }
-
- if (!unevaluated.get<style::FillPattern>().isUndefined()
- || evaluated.get<style::FillColor>().constantOr(Color()).a < 1.0f
- || evaluated.get<style::FillOpacity>().constantOr(0) < 1.0f) {
- passes |= RenderPass::Translucent;
- } else {
- passes |= RenderPass::Opaque;
- }
-}
-
-bool RenderFillLayer::hasTransition() const {
- return unevaluated.hasTransition();
-}
-
-bool RenderFillLayer::queryIntersectsFeature(
- const GeometryCoordinates& queryGeometry,
- const GeometryTileFeature& feature,
- const float,
- const float bearing,
- const float pixelsToTileUnits) const {
-
- auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
- queryGeometry,
- evaluated.get<style::FillTranslate>(),
- evaluated.get<style::FillTranslateAnchor>(),
- bearing,
- pixelsToTileUnits);
-
- return util::polygonIntersectsMultiPolygon(translatedQueryGeometry.value_or(queryGeometry), feature.getGeometries());
-}
-
-
-}
diff --git a/src/mbgl/renderer/render_item.hpp b/src/mbgl/renderer/render_item.hpp
deleted file mode 100644
index 787211c30a..0000000000
--- a/src/mbgl/renderer/render_item.hpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#pragma once
-
-#include <mbgl/util/color.hpp>
-
-#include <unordered_set>
-#include <vector>
-
-namespace mbgl {
-
-class RenderLayer;
-class RenderSource;
-class RenderTile;
-class Bucket;
-
-namespace style {
-} // namespace style
-
-class RenderItem {
-public:
- RenderItem(const RenderLayer& layer_,
- std::vector<std::reference_wrapper<RenderTile>> tiles_ = {})
- : layer(layer_), tiles(std::move(tiles_)) {
- }
-
- const RenderLayer& layer;
- std::vector<std::reference_wrapper<RenderTile>> tiles;
-};
-
-class RenderData {
-public:
- Color backgroundColor;
- std::unordered_set<RenderSource*> sources;
- std::vector<RenderItem> order;
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/render_layer.cpp b/src/mbgl/renderer/render_layer.cpp
index 6699f39144..eb2b74ffe0 100644
--- a/src/mbgl/renderer/render_layer.cpp
+++ b/src/mbgl/renderer/render_layer.cpp
@@ -1,14 +1,55 @@
#include <mbgl/renderer/render_layer.hpp>
+#include <mbgl/renderer/layers/render_background_layer.hpp>
+#include <mbgl/renderer/layers/render_circle_layer.hpp>
+#include <mbgl/renderer/layers/render_custom_layer.hpp>
+#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp>
+#include <mbgl/renderer/layers/render_fill_layer.hpp>
+#include <mbgl/renderer/layers/render_line_layer.hpp>
+#include <mbgl/renderer/layers/render_raster_layer.hpp>
+#include <mbgl/renderer/layers/render_symbol_layer.hpp>
#include <mbgl/style/types.hpp>
+#include <mbgl/renderer/render_tile.hpp>
namespace mbgl {
-RenderLayer::RenderLayer(style::LayerType type_, const style::Layer::Impl& baseImpl_)
- : type(type_), baseImpl(baseImpl_) {
+using namespace style;
+
+std::unique_ptr<RenderLayer> RenderLayer::create(Immutable<Layer::Impl> impl) {
+ switch (impl->type) {
+ case LayerType::Fill:
+ return std::make_unique<RenderFillLayer>(staticImmutableCast<FillLayer::Impl>(impl));
+ case LayerType::Line:
+ return std::make_unique<RenderLineLayer>(staticImmutableCast<LineLayer::Impl>(impl));
+ case LayerType::Circle:
+ return std::make_unique<RenderCircleLayer>(staticImmutableCast<CircleLayer::Impl>(impl));
+ case LayerType::Symbol:
+ return std::make_unique<RenderSymbolLayer>(staticImmutableCast<SymbolLayer::Impl>(impl));
+ case LayerType::Raster:
+ return std::make_unique<RenderRasterLayer>(staticImmutableCast<RasterLayer::Impl>(impl));
+ case LayerType::Background:
+ return std::make_unique<RenderBackgroundLayer>(staticImmutableCast<BackgroundLayer::Impl>(impl));
+ case LayerType::Custom:
+ return std::make_unique<RenderCustomLayer>(staticImmutableCast<CustomLayer::Impl>(impl));
+ case LayerType::FillExtrusion:
+ return std::make_unique<RenderFillExtrusionLayer>(staticImmutableCast<FillExtrusionLayer::Impl>(impl));
+ }
+
+ // Not reachable, but placate GCC.
+ assert(false);
+ return nullptr;
+}
+
+RenderLayer::RenderLayer(style::LayerType type_, Immutable<style::Layer::Impl> baseImpl_)
+ : type(type_),
+ baseImpl(baseImpl_) {
+}
+
+void RenderLayer::setImpl(Immutable<style::Layer::Impl> impl) {
+ baseImpl = impl;
}
const std::string& RenderLayer::getID() const {
- return baseImpl.id;
+ return baseImpl->id;
}
bool RenderLayer::hasRenderPass(RenderPass pass) const {
@@ -17,9 +58,14 @@ bool RenderLayer::hasRenderPass(RenderPass pass) const {
bool RenderLayer::needsRendering(float zoom) const {
return passes != RenderPass::None
- && baseImpl.visibility != style::VisibilityType::None
- && baseImpl.minZoom <= zoom
- && baseImpl.maxZoom >= zoom;
+ && baseImpl->visibility != style::VisibilityType::None
+ && baseImpl->minZoom <= zoom
+ && baseImpl->maxZoom >= zoom;
+}
+
+void RenderLayer::setRenderTiles(std::vector<std::reference_wrapper<RenderTile>> tiles) {
+ renderTiles = std::move(tiles);
}
-} \ No newline at end of file
+} //namespace mbgl
+
diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp
index eea2ec1f61..dfc6bcf2fd 100644
--- a/src/mbgl/renderer/render_layer.hpp
+++ b/src/mbgl/renderer/render_layer.hpp
@@ -12,27 +12,27 @@ namespace mbgl {
class Bucket;
class BucketParameters;
-class CascadeParameters;
+class TransitionParameters;
class PropertyEvaluationParameters;
+class PaintParameters;
+class RenderSource;
+class RenderTile;
class RenderLayer {
-
protected:
- RenderLayer(style::LayerType, const style::Layer::Impl&);
+ RenderLayer(style::LayerType, Immutable<style::Layer::Impl>);
const style::LayerType type;
public:
+ static std::unique_ptr<RenderLayer> create(Immutable<style::Layer::Impl>);
virtual ~RenderLayer() = default;
- // Create an identical copy of this layer.
- virtual std::unique_ptr<RenderLayer> clone() const = 0;
-
- // Partially evaluate paint properties based on a set of classes.
- virtual void cascade(const CascadeParameters&) = 0;
+ // Begin transitions for any properties that have changed since the last frame.
+ virtual void transition(const TransitionParameters&) = 0;
- // Fully evaluate cascaded paint properties based on a zoom level.
+ // Fully evaluate possibly-transitioning paint properties based on a zoom level.
virtual void evaluate(const PropertyEvaluationParameters&) = 0;
// Returns true if any paint properties have active transitions.
@@ -61,6 +61,8 @@ public:
// Checks whether this layer can be rendered.
bool needsRendering(float zoom) const;
+ virtual void render(PaintParameters&, RenderSource*) = 0;
+
// Check wether the given geometry intersects
// with the feature
virtual bool queryIntersectsFeature(
@@ -72,15 +74,21 @@ public:
virtual std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const = 0;
+ void setRenderTiles(std::vector<std::reference_wrapper<RenderTile>>);
// Private implementation
- const style::Layer::Impl& baseImpl;
+ Immutable<style::Layer::Impl> baseImpl;
+ void setImpl(Immutable<style::Layer::Impl>);
friend std::string layoutKey(const RenderLayer&);
-protected:
+protected:
// 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_light.cpp b/src/mbgl/renderer/render_light.cpp
index 134e1829e0..85768cff47 100644
--- a/src/mbgl/renderer/render_light.cpp
+++ b/src/mbgl/renderer/render_light.cpp
@@ -2,25 +2,17 @@
namespace mbgl {
-RenderLight::RenderLight(std::shared_ptr<const style::Light::Impl> impl_)
- : impl(std::move(impl_)) {
+RenderLight::RenderLight(Immutable<style::Light::Impl> impl_)
+ : impl(std::move(impl_)),
+ transitioning(impl->properties.untransitioned()) {
}
-RenderLight::RenderLight(std::shared_ptr<const style::Light::Impl> impl_, const TransitioningLight transitioning_)
- : impl(std::move(impl_))
- , transitioning(transitioning_) {
-}
-
-std::unique_ptr<RenderLight> RenderLight::copy(std::shared_ptr<const style::Light::Impl> impl_) const {
- return std::make_unique<RenderLight>(std::move(impl_), transitioning);
-}
-
-void RenderLight::transition(const CascadeParameters& parameters) {
- transitioning = TransitioningLight(impl->properties, std::move(transitioning), parameters);
+void RenderLight::transition(const TransitionParameters& parameters) {
+ transitioning = impl->properties.transitioned(parameters, std::move(transitioning));
}
void RenderLight::evaluate(const PropertyEvaluationParameters& parameters) {
- evaluated = EvaluatedLight(transitioning, parameters);
+ evaluated = transitioning.evaluate(parameters);
}
bool RenderLight::hasTransition() const {
diff --git a/src/mbgl/renderer/render_light.hpp b/src/mbgl/renderer/render_light.hpp
index 275f3ae8ba..f13f925318 100644
--- a/src/mbgl/renderer/render_light.hpp
+++ b/src/mbgl/renderer/render_light.hpp
@@ -1,98 +1,29 @@
#pragma once
#include <mbgl/style/light_impl.hpp>
-#include <mbgl/style/light_properties.hpp>
-#include <mbgl/renderer/transitioning_property.hpp>
-#include <mbgl/renderer/cascade_parameters.hpp>
-#include <mbgl/renderer/property_evaluator.hpp>
-#include <mbgl/renderer/property_evaluation_parameters.hpp>
-#include <mbgl/util/ignore.hpp>
-
-#include <memory>
+#include <mbgl/util/immutable.hpp>
namespace mbgl {
-template <class TypeList>
-class Transitioning;
-
-template <class... Ps>
-class Transitioning<TypeList<Ps...>> : public IndexedTuple<
- TypeList<Ps...>,
- TypeList<TransitioningProperty<typename Ps::ValueType>...>>
-{
-private:
- using Properties = TypeList<Ps...>;
- using Raw = IndexedTuple<Properties, Properties>;
- using Super = IndexedTuple<
- TypeList<Ps...>,
- TypeList<TransitioningProperty<typename Ps::ValueType>...>>;
-
-public:
- Transitioning() = default;
- Transitioning(const Raw& raw, Transitioning&& prior, const CascadeParameters& params)
- : Super {
- TransitioningProperty<typename Ps::ValueType>(
- raw.template get<Ps>().value,
- std::move(prior.template get<Ps>()),
- raw.template get<Ps>().transition.reverseMerge(params.transition),
- params.now)...
- } {}
-
- bool hasTransition() const {
- bool result = false;
- util::ignore({ result |= this->template get<Ps>().hasTransition()... });
- return result;
- }
-};
-
-template <class TypeList>
-class Evaluated;
+class TransitionParameters;
+class PropertyEvaluationParameters;
-template <class... Ps>
-class Evaluated<TypeList<Ps...>> : public IndexedTuple<
- TypeList<Ps...>,
- TypeList<typename Ps::Type...>>
-{
-private:
- using Properties = TypeList<Ps...>;
- using TransitioningPs = Transitioning<Properties>;
- using Super = IndexedTuple<
- TypeList<Ps...>,
- TypeList<typename Ps::Type...>>;
-
-public:
- Evaluated() = default;
- Evaluated(TransitioningPs& transitioning, const PropertyEvaluationParameters& params)
- : Super {
- transitioning.template get<Ps>()
- .evaluate(PropertyEvaluator<typename Ps::Type>(params, Ps::defaultValue()), params.now)...
- } {}
-};
-
-using TransitioningLight = Transitioning<style::LightProperties>;
-using EvaluatedLight = Evaluated<style::LightProperties>;
+using TransitioningLight = style::LightProperties::Unevaluated;
+using EvaluatedLight = style::LightProperties::PossiblyEvaluated;
class RenderLight {
public:
- RenderLight(std::shared_ptr<const style::Light::Impl>);
-
- // Creates a copy intitalized with previous transitioning light
- RenderLight(std::shared_ptr<const style::Light::Impl>, const TransitioningLight);
+ RenderLight(Immutable<style::Light::Impl>);
- // creates a copy initialized with previous transitioning
- // values
- std::unique_ptr<RenderLight> copy(std::shared_ptr<const style::Light::Impl>) const;
-
- void transition(const CascadeParameters&);
+ void transition(const TransitionParameters&);
void evaluate(const PropertyEvaluationParameters&);
bool hasTransition() const;
const EvaluatedLight& getEvaluated() const;
- const std::shared_ptr<const style::Light::Impl> impl;
+ Immutable<style::Light::Impl> impl;
private:
-
TransitioningLight transitioning;
EvaluatedLight evaluated;
};
diff --git a/src/mbgl/renderer/render_line_layer.cpp b/src/mbgl/renderer/render_line_layer.cpp
deleted file mode 100644
index 06c2564516..0000000000
--- a/src/mbgl/renderer/render_line_layer.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-#include <mbgl/renderer/render_line_layer.hpp>
-#include <mbgl/renderer/line_bucket.hpp>
-#include <mbgl/style/layers/line_layer_impl.hpp>
-#include <mbgl/geometry/feature_index.hpp>
-#include <mbgl/util/math.hpp>
-#include <mbgl/util/intersection_tests.hpp>
-
-namespace mbgl {
-
-RenderLineLayer::RenderLineLayer(const style::LineLayer::Impl& _impl)
- : RenderLayer(style::LayerType::Line, _impl),
- impl(&_impl) {
-}
-
-std::unique_ptr<RenderLayer> RenderLineLayer::clone() const {
- return std::make_unique<RenderLineLayer>(*this);
-}
-
-std::unique_ptr<Bucket> RenderLineLayer::createBucket(const BucketParameters& parameters, const std::vector<const RenderLayer*>& layers) const {
- return std::make_unique<LineBucket>(parameters, layers, impl->layout);
-}
-
-void RenderLineLayer::cascade(const CascadeParameters& parameters) {
- unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated));
-}
-
-void RenderLineLayer::evaluate(const PropertyEvaluationParameters& parameters) {
- // for scaling dasharrays
- auto dashArrayParams = parameters;
- dashArrayParams.z = std::floor(dashArrayParams.z);
- dashLineWidth = unevaluated.evaluate<style::LineWidth>(dashArrayParams);
-
- evaluated = unevaluated.evaluate(parameters);
-
- passes = (evaluated.get<style::LineOpacity>().constantOr(1.0) > 0
- && evaluated.get<style::LineColor>().constantOr(Color::black()).a > 0
- && evaluated.get<style::LineWidth>() > 0)
- ? RenderPass::Translucent : RenderPass::None;
-}
-
-bool RenderLineLayer::hasTransition() const {
- return unevaluated.hasTransition();
-}
-
-optional<GeometryCollection> offsetLine(const GeometryCollection& rings, const double offset) {
- if (offset == 0) return {};
-
- GeometryCollection newRings;
- Point<double> zero(0, 0);
- for (const auto& ring : rings) {
- newRings.emplace_back();
- auto& newRing = newRings.back();
-
- for (auto i = ring.begin(); i != ring.end(); i++) {
- auto& p = *i;
-
- Point<double> aToB = i == ring.begin() ?
- zero :
- util::perp(util::unit(convertPoint<double>(p - *(i - 1))));
- Point<double> bToC = i + 1 == ring.end() ?
- zero :
- util::perp(util::unit(convertPoint<double>(*(i + 1) - p)));
- Point<double> extrude = util::unit(aToB + bToC);
-
- const double cosHalfAngle = extrude.x * bToC.x + extrude.y * bToC.y;
- extrude *= (1.0 / cosHalfAngle);
-
- newRing.push_back(convertPoint<int16_t>(extrude * offset) + p);
- }
- }
-
- return newRings;
-}
-
-bool RenderLineLayer::queryIntersectsFeature(
- const GeometryCoordinates& queryGeometry,
- const GeometryTileFeature& feature,
- const float zoom,
- const float bearing,
- const float pixelsToTileUnits) const {
-
- // Translate query geometry
- auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
- queryGeometry,
- evaluated.get<style::LineTranslate>(),
- evaluated.get<style::LineTranslateAnchor>(),
- bearing,
- pixelsToTileUnits);
-
- // Evaluate function
- auto offset = evaluated.get<style::LineOffset>()
- .evaluate(feature, zoom, style::LineOffset::defaultValue()) * pixelsToTileUnits;
-
- // Apply offset to geometry
- auto offsetGeometry = offsetLine(feature.getGeometries(), offset);
-
- // Test intersection
- const float halfWidth = getLineWidth(feature, zoom) / 2.0 * pixelsToTileUnits;
- return util::polygonIntersectsBufferedMultiLine(
- translatedQueryGeometry.value_or(queryGeometry),
- offsetGeometry.value_or(feature.getGeometries()),
- halfWidth);
-}
-
-float RenderLineLayer::getLineWidth(const GeometryTileFeature& feature, const float zoom) const {
- float lineWidth = evaluated.get<style::LineWidth>();
- float gapWidth = evaluated.get<style::LineGapWidth>()
- .evaluate(feature, zoom, style::LineGapWidth::defaultValue());
- if (gapWidth) {
- return gapWidth + 2 * lineWidth;
- } else {
- return lineWidth;
- }
-}
-
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/render_pass.hpp b/src/mbgl/renderer/render_pass.hpp
index d273e34ff7..5d18304129 100644
--- a/src/mbgl/renderer/render_pass.hpp
+++ b/src/mbgl/renderer/render_pass.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/util/traits.hpp>
+#include <mbgl/util/util.hpp>
#include <cstdint>
@@ -10,17 +11,18 @@ enum class RenderPass : uint8_t {
None = 0,
Opaque = 1 << 0,
Translucent = 1 << 1,
+ Pass3D = 1 << 2,
};
-constexpr RenderPass operator|(RenderPass a, RenderPass b) {
+MBGL_CONSTEXPR RenderPass operator|(RenderPass a, RenderPass b) {
return RenderPass(mbgl::underlying_type(a) | mbgl::underlying_type(b));
}
-constexpr RenderPass& operator|=(RenderPass& a, RenderPass b) {
+MBGL_CONSTEXPR RenderPass& operator|=(RenderPass& a, RenderPass b) {
return (a = a | b);
}
-constexpr RenderPass operator&(RenderPass a, RenderPass b) {
+MBGL_CONSTEXPR RenderPass operator&(RenderPass a, RenderPass b) {
return RenderPass(mbgl::underlying_type(a) & mbgl::underlying_type(b));
}
diff --git a/src/mbgl/renderer/render_raster_layer.cpp b/src/mbgl/renderer/render_raster_layer.cpp
deleted file mode 100644
index 5e664e6f58..0000000000
--- a/src/mbgl/renderer/render_raster_layer.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <mbgl/renderer/render_raster_layer.hpp>
-#include <mbgl/renderer/bucket.hpp>
-#include <mbgl/style/layers/raster_layer_impl.hpp>
-
-namespace mbgl {
-
-RenderRasterLayer::RenderRasterLayer(const style::RasterLayer::Impl& _impl)
- : RenderLayer(style::LayerType::Raster, _impl),
- impl(&_impl) {
-}
-
-std::unique_ptr<RenderLayer> RenderRasterLayer::clone() const {
- return std::make_unique<RenderRasterLayer>(*this);
-}
-
-std::unique_ptr<Bucket> RenderRasterLayer::createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const {
- assert(false);
- return nullptr;
-}
-
-void RenderRasterLayer::cascade(const CascadeParameters& parameters) {
- unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated));
-}
-
-void RenderRasterLayer::evaluate(const PropertyEvaluationParameters& parameters) {
- evaluated = unevaluated.evaluate(parameters);
-
- passes = evaluated.get<style::RasterOpacity>() > 0 ? RenderPass::Translucent : RenderPass::None;
-}
-
-bool RenderRasterLayer::hasTransition() const {
- return unevaluated.hasTransition();
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/render_source.cpp b/src/mbgl/renderer/render_source.cpp
index 643d92fe81..7723a1c7ca 100644
--- a/src/mbgl/renderer/render_source.cpp
+++ b/src/mbgl/renderer/render_source.cpp
@@ -1,12 +1,42 @@
#include <mbgl/renderer/render_source.hpp>
#include <mbgl/renderer/render_source_observer.hpp>
+#include <mbgl/renderer/sources/render_geojson_source.hpp>
+#include <mbgl/renderer/sources/render_raster_source.hpp>
+#include <mbgl/renderer/sources/render_vector_source.hpp>
+#include <mbgl/renderer/tile_parameters.hpp>
+#include <mbgl/annotation/render_annotation_source.hpp>
+#include <mbgl/renderer/sources/render_image_source.hpp>
#include <mbgl/tile/tile.hpp>
namespace mbgl {
+using namespace style;
+
+std::unique_ptr<RenderSource> RenderSource::create(Immutable<Source::Impl> impl) {
+ switch (impl->type) {
+ case SourceType::Vector:
+ return std::make_unique<RenderVectorSource>(staticImmutableCast<VectorSource::Impl>(impl));
+ case SourceType::Raster:
+ return std::make_unique<RenderRasterSource>(staticImmutableCast<RasterSource::Impl>(impl));
+ case SourceType::GeoJSON:
+ return std::make_unique<RenderGeoJSONSource>(staticImmutableCast<GeoJSONSource::Impl>(impl));
+ case SourceType::Video:
+ assert(false);
+ return nullptr;
+ case SourceType::Annotations:
+ return std::make_unique<RenderAnnotationSource>(staticImmutableCast<AnnotationSource::Impl>(impl));
+ case SourceType::Image:
+ return std::make_unique<RenderImageSource>(staticImmutableCast<ImageSource::Impl>(impl));
+ }
+
+ // Not reachable, but placate GCC.
+ assert(false);
+ return nullptr;
+}
+
static RenderSourceObserver nullObserver;
-RenderSource::RenderSource(const style::Source::Impl& impl)
+RenderSource::RenderSource(Immutable<style::Source::Impl> impl)
: baseImpl(impl),
observer(&nullObserver) {
}
@@ -23,4 +53,8 @@ void RenderSource::onTileError(Tile& tile, std::exception_ptr error) {
observer->onTileError(*this, tile.id, error);
}
+bool RenderSource::isEnabled() const {
+ return enabled;
}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_source.hpp b/src/mbgl/renderer/render_source.hpp
index d31347579e..8293923ff6 100644
--- a/src/mbgl/renderer/render_source.hpp
+++ b/src/mbgl/renderer/render_source.hpp
@@ -6,6 +6,7 @@
#include <mbgl/util/geo.hpp>
#include <mbgl/util/feature.hpp>
#include <mbgl/style/source_impl.hpp>
+#include <mbgl/style/layer_impl.hpp>
#include <unordered_map>
#include <vector>
@@ -14,69 +15,73 @@
namespace mbgl {
-class Painter;
+class PaintParameters;
class TransformState;
class RenderTile;
+class RenderLayer;
class RenderedQueryOptions;
class SourceQueryOptions;
class Tile;
class RenderSourceObserver;
class TileParameters;
-namespace algorithm {
-class ClipIDGenerator;
-} // namespace algorithm
-
class RenderSource : protected TileObserver {
public:
- RenderSource(const style::Source::Impl&);
- virtual ~RenderSource() = default;
+ static std::unique_ptr<RenderSource> create(Immutable<style::Source::Impl>);
- virtual bool isLoaded() const = 0;
+ // Check whether this source is of the given subtype.
+ template <class T>
+ bool is() const;
- // Called when the camera has changed. May load new tiles, unload obsolete tiles, or
- // trigger re-placement of existing complete tiles.
- virtual void updateTiles(const TileParameters&) = 0;
+ // Dynamically cast this source to the given subtype.
+ template <class T>
+ T* as() {
+ return is<T>() ? reinterpret_cast<T*>(this) : nullptr;
+ }
- // Removes all tiles (by putting them into the cache).
- virtual void removeTiles() = 0;
+ template <class T>
+ const T* as() const {
+ return is<T>() ? reinterpret_cast<const T*>(this) : nullptr;
+ }
- // Remove all tiles and clear the cache.
- virtual void invalidateTiles() = 0;
+ bool isEnabled() const;
+ virtual bool isLoaded() const = 0;
- // Request that all loaded tiles re-run the layout operation on the existing source
- // data with fresh style information.
- virtual void reloadTiles() = 0;
+ virtual void update(Immutable<style::Source::Impl>,
+ const std::vector<Immutable<style::Layer::Impl>>&,
+ bool needsRendering,
+ bool needsRelayout,
+ const TileParameters&) = 0;
- virtual void startRender(algorithm::ClipIDGenerator&,
- const mat4& projMatrix,
- const mat4& clipMatrix,
- const TransformState&) = 0;
- virtual void finishRender(Painter&) = 0;
+ virtual void startRender(PaintParameters&) = 0;
+ virtual void finishRender(PaintParameters&) = 0;
- virtual std::map<UnwrappedTileID, RenderTile>& getRenderTiles() = 0;
+ // Returns an unsorted list of RenderTiles.
+ virtual std::vector<std::reference_wrapper<RenderTile>> getRenderTiles() = 0;
virtual 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 = 0;
virtual std::vector<Feature>
querySourceFeatures(const SourceQueryOptions&) const = 0;
- virtual void setCacheSize(size_t) = 0;
virtual void onLowMemory() = 0;
virtual void dumpDebugLogs() const = 0;
void setObserver(RenderSourceObserver*);
- const style::Source::Impl& baseImpl;
- bool enabled = false;
+ Immutable<style::Source::Impl> baseImpl;
protected:
+ RenderSource(Immutable<style::Source::Impl>);
RenderSourceObserver* observer;
+ bool enabled = false;
+
void onTileChanged(Tile&) final;
void onTileError(Tile&, std::exception_ptr) final;
};
diff --git a/src/mbgl/renderer/render_static_data.cpp b/src/mbgl/renderer/render_static_data.cpp
new file mode 100644
index 0000000000..ccf239e643
--- /dev/null
+++ b/src/mbgl/renderer/render_static_data.cpp
@@ -0,0 +1,67 @@
+#include <mbgl/renderer/render_static_data.hpp>
+#include <mbgl/programs/program_parameters.hpp>
+
+namespace mbgl {
+
+static gl::VertexVector<FillLayoutVertex> tileVertices() {
+ gl::VertexVector<FillLayoutVertex> result;
+ result.emplace_back(FillProgram::layoutVertex({ 0, 0 }));
+ result.emplace_back(FillProgram::layoutVertex({ util::EXTENT, 0 }));
+ result.emplace_back(FillProgram::layoutVertex({ 0, util::EXTENT }));
+ result.emplace_back(FillProgram::layoutVertex({ util::EXTENT, util::EXTENT }));
+ return result;
+}
+
+static gl::IndexVector<gl::Triangles> quadTriangleIndices() {
+ gl::IndexVector<gl::Triangles> result;
+ result.emplace_back(0, 1, 2);
+ result.emplace_back(1, 2, 3);
+ return result;
+}
+
+static gl::IndexVector<gl::LineStrip> tileLineStripIndices() {
+ gl::IndexVector<gl::LineStrip> result;
+ result.emplace_back(0);
+ result.emplace_back(1);
+ result.emplace_back(3);
+ result.emplace_back(2);
+ result.emplace_back(0);
+ return result;
+}
+
+static gl::VertexVector<RasterLayoutVertex> rasterVertices() {
+ gl::VertexVector<RasterLayoutVertex> result;
+ result.emplace_back(RasterProgram::layoutVertex({ 0, 0 }, { 0, 0 }));
+ result.emplace_back(RasterProgram::layoutVertex({ util::EXTENT, 0 }, { util::EXTENT, 0 }));
+ result.emplace_back(RasterProgram::layoutVertex({ 0, util::EXTENT }, { 0, util::EXTENT }));
+ result.emplace_back(RasterProgram::layoutVertex({ util::EXTENT, util::EXTENT }, { util::EXTENT, util::EXTENT }));
+ return result;
+}
+
+static gl::VertexVector<ExtrusionTextureLayoutVertex> extrusionTextureVertices() {
+ gl::VertexVector<ExtrusionTextureLayoutVertex> result;
+ result.emplace_back(ExtrusionTextureProgram::layoutVertex({ 0, 0 }));
+ result.emplace_back(ExtrusionTextureProgram::layoutVertex({ 1, 0 }));
+ result.emplace_back(ExtrusionTextureProgram::layoutVertex({ 0, 1 }));
+ result.emplace_back(ExtrusionTextureProgram::layoutVertex({ 1, 1 }));
+ return result;
+}
+
+RenderStaticData::RenderStaticData(gl::Context& context, float pixelRatio, const optional<std::string>& programCacheDir)
+ : tileVertexBuffer(context.createVertexBuffer(tileVertices())),
+ rasterVertexBuffer(context.createVertexBuffer(rasterVertices())),
+ extrusionTextureVertexBuffer(context.createVertexBuffer(extrusionTextureVertices())),
+ quadTriangleIndexBuffer(context.createIndexBuffer(quadTriangleIndices())),
+ tileBorderIndexBuffer(context.createIndexBuffer(tileLineStripIndices())),
+ programs(context, ProgramParameters { pixelRatio, false, programCacheDir })
+#ifndef NDEBUG
+ , overdrawPrograms(context, ProgramParameters { pixelRatio, true, programCacheDir })
+#endif
+{
+ tileTriangleSegments.emplace_back(0, 0, 4, 6);
+ tileBorderSegments.emplace_back(0, 0, 4, 5);
+ rasterSegments.emplace_back(0, 0, 4, 6);
+ extrusionTextureSegments.emplace_back(0, 0, 4, 6);
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_static_data.hpp b/src/mbgl/renderer/render_static_data.hpp
new file mode 100644
index 0000000000..cf58c31f4d
--- /dev/null
+++ b/src/mbgl/renderer/render_static_data.hpp
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <mbgl/gl/vertex_buffer.hpp>
+#include <mbgl/gl/index_buffer.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/util/optional.hpp>
+
+#include <string>
+
+namespace mbgl {
+
+class RenderStaticData {
+public:
+ RenderStaticData(gl::Context&, float pixelRatio, const optional<std::string>& programCacheDir);
+
+ gl::VertexBuffer<FillLayoutVertex> tileVertexBuffer;
+ gl::VertexBuffer<RasterLayoutVertex> rasterVertexBuffer;
+ gl::VertexBuffer<ExtrusionTextureLayoutVertex> extrusionTextureVertexBuffer;
+
+ gl::IndexBuffer<gl::Triangles> quadTriangleIndexBuffer;
+ gl::IndexBuffer<gl::LineStrip> tileBorderIndexBuffer;
+
+ SegmentVector<FillAttributes> tileTriangleSegments;
+ SegmentVector<DebugAttributes> tileBorderSegments;
+ SegmentVector<RasterAttributes> rasterSegments;
+ SegmentVector<ExtrusionTextureAttributes> extrusionTextureSegments;
+
+ optional<gl::Renderbuffer<gl::RenderbufferType::DepthComponent>> depthRenderbuffer;
+ bool has3D = false;
+ Size backendSize;
+
+ Programs programs;
+
+#ifndef NDEBUG
+ Programs overdrawPrograms;
+#endif
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/render_symbol_layer.cpp b/src/mbgl/renderer/render_symbol_layer.cpp
deleted file mode 100644
index 30d769e032..0000000000
--- a/src/mbgl/renderer/render_symbol_layer.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-#include <mbgl/renderer/render_symbol_layer.hpp>
-#include <mbgl/layout/symbol_layout.hpp>
-#include <mbgl/renderer/bucket.hpp>
-#include <mbgl/renderer/bucket_parameters.hpp>
-#include <mbgl/renderer/property_evaluation_parameters.hpp>
-#include <mbgl/style/layers/symbol_layer_impl.hpp>
-#include <mbgl/tile/geometry_tile_data.hpp>
-
-namespace mbgl {
-
-RenderSymbolLayer::RenderSymbolLayer(const style::SymbolLayer::Impl& _impl)
- : RenderLayer(style::LayerType::Symbol, _impl),
- impl(&_impl) {
-}
-
-std::unique_ptr<RenderLayer> RenderSymbolLayer::clone() const {
- return std::make_unique<RenderSymbolLayer>(*this);
-}
-
-std::unique_ptr<Bucket> RenderSymbolLayer::createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const {
- assert(false); // Should be calling createLayout() instead.
- return nullptr;
-}
-
-std::unique_ptr<SymbolLayout> RenderSymbolLayer::createLayout(const BucketParameters& parameters,
- const std::vector<const RenderLayer*>& group,
- const GeometryTileLayer& layer,
- GlyphDependencies& glyphDependencies,
- IconDependencies& iconDependencies) const {
- return std::make_unique<SymbolLayout>(parameters,
- group,
- layer,
- iconDependencies,
- glyphDependencies);
-}
-
-void RenderSymbolLayer::cascade(const CascadeParameters& parameters) {
- unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated));
-}
-
-void RenderSymbolLayer::evaluate(const PropertyEvaluationParameters& parameters) {
- evaluated = unevaluated.evaluate(parameters);
-
- auto hasIconOpacity = evaluated.get<style::IconColor>().constantOr(Color::black()).a > 0 ||
- evaluated.get<style::IconHaloColor>().constantOr(Color::black()).a > 0;
- auto hasTextOpacity = evaluated.get<style::TextColor>().constantOr(Color::black()).a > 0 ||
- evaluated.get<style::TextHaloColor>().constantOr(Color::black()).a > 0;
-
- passes = ((evaluated.get<style::IconOpacity>().constantOr(1) > 0 && hasIconOpacity && iconSize > 0)
- || (evaluated.get<style::TextOpacity>().constantOr(1) > 0 && hasTextOpacity && textSize > 0))
- ? RenderPass::Translucent : RenderPass::None;
-}
-
-bool RenderSymbolLayer::hasTransition() const {
- return unevaluated.hasTransition();
-}
-
-style::IconPaintProperties::Evaluated RenderSymbolLayer::iconPaintProperties() const {
- return style::IconPaintProperties::Evaluated {
- evaluated.get<style::IconOpacity>(),
- evaluated.get<style::IconColor>(),
- evaluated.get<style::IconHaloColor>(),
- evaluated.get<style::IconHaloWidth>(),
- evaluated.get<style::IconHaloBlur>(),
- evaluated.get<style::IconTranslate>(),
- evaluated.get<style::IconTranslateAnchor>()
- };
-}
-
-style::TextPaintProperties::Evaluated RenderSymbolLayer::textPaintProperties() const {
- return style::TextPaintProperties::Evaluated {
- evaluated.get<style::TextOpacity>(),
- evaluated.get<style::TextColor>(),
- evaluated.get<style::TextHaloColor>(),
- evaluated.get<style::TextHaloWidth>(),
- evaluated.get<style::TextHaloBlur>(),
- evaluated.get<style::TextTranslate>(),
- evaluated.get<style::TextTranslateAnchor>()
- };
-}
-
-
-style::SymbolPropertyValues RenderSymbolLayer::iconPropertyValues(const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) const {
- return style::SymbolPropertyValues {
- layout_.get<style::IconRotationAlignment>(), // icon-pitch-alignment is not yet implemented; inherit the rotation alignment
- layout_.get<style::IconRotationAlignment>(),
- layout_.get<style::IconSize>(),
- evaluated.get<style::IconTranslate>(),
- evaluated.get<style::IconTranslateAnchor>(),
- iconSize,
- 1.0f,
- evaluated.get<style::IconHaloColor>().constantOr(Color::black()).a > 0 &&
- evaluated.get<style::IconHaloWidth>().constantOr(1),
- evaluated.get<style::IconColor>().constantOr(Color::black()).a > 0
- };
-}
-
-style::SymbolPropertyValues RenderSymbolLayer::textPropertyValues(const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) const {
- return style::SymbolPropertyValues {
- layout_.get<style::TextPitchAlignment>(),
- layout_.get<style::TextRotationAlignment>(),
- layout_.get<style::TextSize>(),
- evaluated.get<style::TextTranslate>(),
- evaluated.get<style::TextTranslateAnchor>(),
- textSize,
- 24.0f,
- evaluated.get<style::TextHaloColor>().constantOr(Color::black()).a > 0 &&
- evaluated.get<style::TextHaloWidth>().constantOr(1),
- evaluated.get<style::TextColor>().constantOr(Color::black()).a > 0
- };
-}
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/render_tile.cpp b/src/mbgl/renderer/render_tile.cpp
index ce59186e61..8df31f8d7c 100644
--- a/src/mbgl/renderer/render_tile.cpp
+++ b/src/mbgl/renderer/render_tile.cpp
@@ -1,5 +1,11 @@
#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/buckets/debug_bucket.hpp>
+#include <mbgl/renderer/render_static_data.hpp>
+#include <mbgl/programs/programs.hpp>
#include <mbgl/map/transform_state.hpp>
+#include <mbgl/tile/tile.hpp>
+#include <mbgl/util/math.hpp>
namespace mbgl {
@@ -8,24 +14,26 @@ using namespace style;
mat4 RenderTile::translateVtxMatrix(const mat4& tileMatrix,
const std::array<float, 2>& translation,
TranslateAnchorType anchor,
- const TransformState& state) const {
+ const TransformState& state,
+ const bool inViewportPixelUnits) const {
if (translation[0] == 0 && translation[1] == 0) {
return tileMatrix;
}
mat4 vtxMatrix;
- if (anchor == TranslateAnchorType::Viewport) {
- const double sin_a = std::sin(-state.getAngle());
- const double cos_a = std::cos(-state.getAngle());
- matrix::translate(vtxMatrix, tileMatrix,
- id.pixelsToTileUnits(translation[0] * cos_a - translation[1] * sin_a, state.getZoom()),
- id.pixelsToTileUnits(translation[0] * sin_a + translation[1] * cos_a, state.getZoom()),
- 0);
+ const float angle = inViewportPixelUnits ?
+ (anchor == TranslateAnchorType::Map ? state.getAngle() : 0) :
+ (anchor == TranslateAnchorType::Viewport ? -state.getAngle() : 0);
+
+ Point<float> translate = util::rotate(Point<float>{ translation[0], translation[1] }, angle);
+
+ if (inViewportPixelUnits) {
+ matrix::translate(vtxMatrix, tileMatrix, translate.x, translate.y, 0);
} else {
matrix::translate(vtxMatrix, tileMatrix,
- id.pixelsToTileUnits(translation[0], state.getZoom()),
- id.pixelsToTileUnits(translation[1], state.getZoom()),
+ id.pixelsToTileUnits(translate.x, state.getZoom()),
+ id.pixelsToTileUnits(translate.y, state.getZoom()),
0);
}
@@ -35,24 +43,107 @@ mat4 RenderTile::translateVtxMatrix(const mat4& tileMatrix,
mat4 RenderTile::translatedMatrix(const std::array<float, 2>& translation,
TranslateAnchorType anchor,
const TransformState& state) const {
- return translateVtxMatrix(matrix, translation, anchor, state);
+ return translateVtxMatrix(matrix, translation, anchor, state, false);
}
mat4 RenderTile::translatedClipMatrix(const std::array<float, 2>& translation,
TranslateAnchorType anchor,
const TransformState& state) const {
- return translateVtxMatrix(nearClippedMatrix, translation, anchor, state);
+ return translateVtxMatrix(nearClippedMatrix, translation, anchor, state, false);
}
-void RenderTile::calculateMatrices(const mat4& projMatrix,
- const mat4& projClipMatrix,
- const TransformState& transform) {
+void RenderTile::setMask(TileMask&& mask) {
+ tile.setMask(std::move(mask));
+}
+
+void RenderTile::startRender(PaintParameters& parameters) {
+ tile.upload(parameters.context);
+
// Calculate two matrices for this tile: matrix is the standard tile matrix; nearClippedMatrix
// clips the near plane to 100 to save depth buffer precision
- transform.matrixFor(matrix, id);
- transform.matrixFor(nearClippedMatrix, id);
- matrix::multiply(matrix, projMatrix, matrix);
- matrix::multiply(nearClippedMatrix, projClipMatrix, nearClippedMatrix);
+ parameters.state.matrixFor(matrix, id);
+ parameters.state.matrixFor(nearClippedMatrix, id);
+ matrix::multiply(matrix, parameters.projMatrix, matrix);
+ matrix::multiply(nearClippedMatrix, parameters.nearClippedProjMatrix, nearClippedMatrix);
+}
+
+void RenderTile::finishRender(PaintParameters& parameters) {
+ if (!used || parameters.debugOptions == MapDebugOptions::NoDebug)
+ return;
+
+ static const style::Properties<>::PossiblyEvaluated properties {};
+ static const DebugProgram::PaintPropertyBinders paintAttibuteData(properties, 0);
+
+ if (parameters.debugOptions & (MapDebugOptions::Timestamps | MapDebugOptions::ParseStatus)) {
+ if (!tile.debugBucket || tile.debugBucket->renderable != tile.isRenderable() ||
+ tile.debugBucket->complete != tile.isComplete() ||
+ !(tile.debugBucket->modified == tile.modified) ||
+ !(tile.debugBucket->expires == tile.expires) ||
+ tile.debugBucket->debugMode != parameters.debugOptions) {
+ tile.debugBucket = std::make_unique<DebugBucket>(
+ tile.id, tile.isRenderable(), tile.isComplete(), tile.modified,
+ tile.expires, parameters.debugOptions, parameters.context);
+ }
+
+ parameters.programs.debug.draw(
+ parameters.context,
+ gl::Lines { 4.0f * parameters.pixelRatio },
+ gl::DepthMode::disabled(),
+ parameters.stencilModeForClipping(clip),
+ gl::ColorMode::unblended(),
+ DebugProgram::UniformValues {
+ uniforms::u_matrix::Value{ matrix },
+ uniforms::u_color::Value{ Color::white() }
+ },
+ *tile.debugBucket->vertexBuffer,
+ *tile.debugBucket->indexBuffer,
+ tile.debugBucket->segments,
+ paintAttibuteData,
+ properties,
+ parameters.state.getZoom(),
+ "debug"
+ );
+
+ parameters.programs.debug.draw(
+ parameters.context,
+ gl::Lines { 2.0f * parameters.pixelRatio },
+ gl::DepthMode::disabled(),
+ parameters.stencilModeForClipping(clip),
+ gl::ColorMode::unblended(),
+ DebugProgram::UniformValues {
+ uniforms::u_matrix::Value{ matrix },
+ uniforms::u_color::Value{ Color::black() }
+ },
+ *tile.debugBucket->vertexBuffer,
+ *tile.debugBucket->indexBuffer,
+ tile.debugBucket->segments,
+ paintAttibuteData,
+ properties,
+ parameters.state.getZoom(),
+ "debug"
+ );
+ }
+
+ if (parameters.debugOptions & MapDebugOptions::TileBorders) {
+ parameters.programs.debug.draw(
+ parameters.context,
+ gl::LineStrip { 4.0f * parameters.pixelRatio },
+ gl::DepthMode::disabled(),
+ parameters.stencilModeForClipping(clip),
+ gl::ColorMode::unblended(),
+ DebugProgram::UniformValues {
+ uniforms::u_matrix::Value{ matrix },
+ uniforms::u_color::Value{ Color::red() }
+ },
+ parameters.staticData.tileVertexBuffer,
+ parameters.staticData.tileBorderIndexBuffer,
+ parameters.staticData.tileBorderSegments,
+ paintAttibuteData,
+ properties,
+ parameters.state.getZoom(),
+ "debug"
+ );
+ }
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/render_tile.hpp b/src/mbgl/renderer/render_tile.hpp
index 02e8667eec..b498972f5c 100644
--- a/src/mbgl/renderer/render_tile.hpp
+++ b/src/mbgl/renderer/render_tile.hpp
@@ -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>
@@ -11,8 +12,9 @@ namespace mbgl {
class Tile;
class TransformState;
+class PaintParameters;
-class RenderTile {
+class RenderTile final {
public:
RenderTile(UnwrappedTileID id_, Tile& tile_) : id(std::move(id_)), tile(tile_) {}
RenderTile(const RenderTile&) = delete;
@@ -35,14 +37,15 @@ public:
style::TranslateAnchorType anchor,
const TransformState&) const;
- void calculateMatrices(const mat4& projMatrix,
- const mat4& projClipMatrix,
- const TransformState&);
-private:
+ void setMask(TileMask&&);
+ void startRender(PaintParameters&);
+ void finishRender(PaintParameters&);
+
mat4 translateVtxMatrix(const mat4& tileMatrix,
const std::array<float, 2>& translation,
style::TranslateAnchorType anchor,
- const TransformState& state) const;
+ const TransformState& state,
+ const bool inViewportPixelUnits) const;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/renderer.cpp b/src/mbgl/renderer/renderer.cpp
new file mode 100644
index 0000000000..e915f5e146
--- /dev/null
+++ b/src/mbgl/renderer/renderer.cpp
@@ -0,0 +1,86 @@
+#include <mbgl/renderer/renderer.hpp>
+#include <mbgl/renderer/renderer_impl.hpp>
+#include <mbgl/renderer/backend_scope.hpp>
+#include <mbgl/annotation/annotation_manager.hpp>
+
+namespace mbgl {
+
+Renderer::Renderer(RendererBackend& backend,
+ float pixelRatio_,
+ FileSource& fileSource_,
+ Scheduler& scheduler_,
+ GLContextMode contextMode_,
+ const optional<std::string> programCacheDir_)
+ : impl(std::make_unique<Impl>(backend, pixelRatio_, fileSource_, scheduler_,
+ contextMode_, std::move(programCacheDir_))) {
+}
+
+Renderer::~Renderer() {
+ BackendScope guard { impl->backend };
+ impl.reset();
+}
+
+void Renderer::markContextLost() {
+ impl->markContextLost();
+}
+
+void Renderer::setObserver(RendererObserver* observer) {
+ impl->setObserver(observer);
+}
+
+void Renderer::render(const UpdateParameters& updateParameters) {
+ impl->render(updateParameters);
+}
+
+std::vector<Feature> Renderer::queryRenderedFeatures(const ScreenLineString& geometry, const RenderedQueryOptions& options) const {
+ return impl->queryRenderedFeatures(geometry, options);
+}
+
+std::vector<Feature> Renderer::queryRenderedFeatures(const ScreenCoordinate& point, const RenderedQueryOptions& options) const {
+ return impl->queryRenderedFeatures({ point }, options);
+}
+
+std::vector<Feature> Renderer::queryRenderedFeatures(const ScreenBox& box, const RenderedQueryOptions& options) const {
+ return impl->queryRenderedFeatures(
+ {
+ box.min,
+ {box.max.x, box.min.y},
+ box.max,
+ {box.min.x, box.max.y},
+ box.min
+ },
+ options
+ );
+}
+
+AnnotationIDs Renderer::queryPointAnnotations(const ScreenBox& box) const {
+ RenderedQueryOptions options;
+ options.layerIDs = {{ AnnotationManager::PointLayerID }};
+ auto features = queryRenderedFeatures(box, options);
+ std::set<AnnotationID> set;
+ for (auto &feature : features) {
+ assert(feature.id);
+ assert(feature.id->is<uint64_t>());
+ assert(feature.id->get<uint64_t>() <= std::numeric_limits<AnnotationID>::max());
+ set.insert(static_cast<AnnotationID>(feature.id->get<uint64_t>()));
+ }
+ AnnotationIDs ids;
+ ids.reserve(set.size());
+ std::move(set.begin(), set.end(), std::back_inserter(ids));
+ return ids;
+}
+
+std::vector<Feature> Renderer::querySourceFeatures(const std::string& sourceID, const SourceQueryOptions& options) const {
+ return impl->querySourceFeatures(sourceID, options);
+}
+
+void Renderer::dumpDebugLogs() {
+ impl->dumDebugLogs();
+}
+
+void Renderer::onLowMemory() {
+ BackendScope guard { impl->backend };
+ impl->onLowMemory();
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/renderer_backend.cpp b/src/mbgl/renderer/renderer_backend.cpp
new file mode 100644
index 0000000000..159ef432b3
--- /dev/null
+++ b/src/mbgl/renderer/renderer_backend.cpp
@@ -0,0 +1,69 @@
+#include <mbgl/renderer/renderer_backend.hpp>
+#include <mbgl/renderer/backend_scope.hpp>
+#include <mbgl/gl/context.hpp>
+#include <mbgl/gl/extension.hpp>
+#include <mbgl/gl/debugging.hpp>
+
+#include <cassert>
+
+namespace mbgl {
+
+RendererBackend::RendererBackend() = default;
+
+gl::Context& RendererBackend::getContext() {
+ assert(BackendScope::exists());
+ std::call_once(initialized, [this] {
+ context = std::make_unique<gl::Context>();
+ context->enableDebugging();
+ context->initializeExtensions(
+ std::bind(&RendererBackend::initializeExtension, this, std::placeholders::_1));
+ });
+ return *context;
+}
+
+PremultipliedImage RendererBackend::readFramebuffer(const Size& size) const {
+ assert(context);
+ return context->readFramebuffer<PremultipliedImage>(size);
+}
+
+void RendererBackend::assumeFramebufferBinding(const gl::FramebufferID fbo) {
+ getContext().bindFramebuffer.setCurrentValue(fbo);
+ if (fbo != ImplicitFramebufferBinding) {
+ assert(gl::value::BindFramebuffer::Get() == getContext().bindFramebuffer.getCurrentValue());
+ }
+}
+
+void RendererBackend::assumeViewport(int32_t x, int32_t y, const Size& size) {
+ getContext().viewport.setCurrentValue({ x, y, size });
+ assert(gl::value::Viewport::Get() == getContext().viewport.getCurrentValue());
+}
+
+void RendererBackend::assumeScissorTest(bool enabled) {
+ getContext().scissorTest.setCurrentValue(enabled);
+ assert(gl::value::ScissorTest::Get() == getContext().scissorTest.getCurrentValue());
+}
+
+bool RendererBackend::implicitFramebufferBound() {
+ return getContext().bindFramebuffer.getCurrentValue() == ImplicitFramebufferBinding;
+}
+
+void RendererBackend::setFramebufferBinding(const gl::FramebufferID fbo) {
+ getContext().bindFramebuffer = fbo;
+ if (fbo != ImplicitFramebufferBinding) {
+ assert(gl::value::BindFramebuffer::Get() == getContext().bindFramebuffer.getCurrentValue());
+ }
+}
+
+void RendererBackend::setViewport(int32_t x, int32_t y, const Size& size) {
+ getContext().viewport = { x, y, size };
+ assert(gl::value::Viewport::Get() == getContext().viewport.getCurrentValue());
+}
+
+void RendererBackend::setScissorTest(bool enabled) {
+ getContext().scissorTest = enabled;
+ assert(gl::value::ScissorTest::Get() == getContext().scissorTest.getCurrentValue());
+}
+
+RendererBackend::~RendererBackend() = default;
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp
new file mode 100644
index 0000000000..1a828b80a3
--- /dev/null
+++ b/src/mbgl/renderer/renderer_impl.cpp
@@ -0,0 +1,742 @@
+#include <mbgl/annotation/annotation_manager.hpp>
+#include <mbgl/renderer/renderer_impl.hpp>
+#include <mbgl/renderer/renderer_backend.hpp>
+#include <mbgl/renderer/renderer_observer.hpp>
+#include <mbgl/renderer/render_source.hpp>
+#include <mbgl/renderer/render_layer.hpp>
+#include <mbgl/renderer/render_static_data.hpp>
+#include <mbgl/renderer/update_parameters.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/transition_parameters.hpp>
+#include <mbgl/renderer/property_evaluation_parameters.hpp>
+#include <mbgl/renderer/tile_parameters.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/layers/render_background_layer.hpp>
+#include <mbgl/renderer/layers/render_custom_layer.hpp>
+#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp>
+#include <mbgl/renderer/style_diff.hpp>
+#include <mbgl/renderer/query.hpp>
+#include <mbgl/renderer/backend_scope.hpp>
+#include <mbgl/renderer/image_manager.hpp>
+#include <mbgl/gl/debugging.hpp>
+#include <mbgl/geometry/line_atlas.hpp>
+#include <mbgl/style/source_impl.hpp>
+#include <mbgl/style/transition_options.hpp>
+#include <mbgl/text/glyph_manager.hpp>
+#include <mbgl/tile/tile.hpp>
+#include <mbgl/util/math.hpp>
+#include <mbgl/util/string.hpp>
+#include <mbgl/util/logging.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+static RendererObserver& nullObserver() {
+ static RendererObserver observer;
+ return observer;
+}
+
+Renderer::Impl::Impl(RendererBackend& backend_,
+ float pixelRatio_,
+ FileSource& fileSource_,
+ Scheduler& scheduler_,
+ GLContextMode contextMode_,
+ const optional<std::string> programCacheDir_)
+ : backend(backend_)
+ , scheduler(scheduler_)
+ , fileSource(fileSource_)
+ , observer(&nullObserver())
+ , contextMode(contextMode_)
+ , pixelRatio(pixelRatio_)
+ , programCacheDir(programCacheDir_)
+ , glyphManager(std::make_unique<GlyphManager>(fileSource))
+ , imageManager(std::make_unique<ImageManager>())
+ , lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 }))
+ , 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>()) {
+ glyphManager->setObserver(this);
+}
+
+Renderer::Impl::~Impl() {
+ assert(BackendScope::exists());
+
+ if (contextLost) {
+ // Signal all RenderCustomLayers that the context was lost
+ // before cleaning up
+ for (const auto& entry : renderLayers) {
+ RenderLayer& layer = *entry.second;
+ if (layer.is<RenderCustomLayer>()) {
+ layer.as<RenderCustomLayer>()->markContextDestroyed();
+ }
+ }
+ }
+};
+
+void Renderer::Impl::setObserver(RendererObserver* observer_) {
+ observer = observer_ ? observer_ : &nullObserver();
+}
+
+void Renderer::Impl::render(const UpdateParameters& updateParameters) {
+ if (updateParameters.mode == MapMode::Still) {
+ // Don't load/render anyting in still mode until explicitly requested.
+ if (!updateParameters.stillImageRequest) {
+ return;
+ }
+
+ // Reset zoom history state.
+ zoomHistory.first = true;
+ }
+
+ assert(BackendScope::exists());
+
+ updateParameters.annotationManager.updateData();
+
+ const bool zoomChanged = zoomHistory.update(updateParameters.transformState.getZoom(), updateParameters.timePoint);
+
+ const TransitionParameters transitionParameters {
+ updateParameters.timePoint,
+ updateParameters.mode == MapMode::Continuous ? updateParameters.transitionOptions : TransitionOptions()
+ };
+
+ const PropertyEvaluationParameters evaluationParameters {
+ zoomHistory,
+ updateParameters.timePoint,
+ updateParameters.mode == MapMode::Continuous ? util::DEFAULT_TRANSITION_DURATION : Duration::zero()
+ };
+
+ const TileParameters tileParameters {
+ updateParameters.pixelRatio,
+ updateParameters.debugOptions,
+ updateParameters.transformState,
+ scheduler,
+ fileSource,
+ updateParameters.mode,
+ updateParameters.annotationManager,
+ *imageManager,
+ *glyphManager,
+ updateParameters.prefetchZoomDelta
+ };
+
+ glyphManager->setURL(updateParameters.glyphURL);
+
+ // Update light.
+ const bool lightChanged = renderLight.impl != updateParameters.light;
+
+ if (lightChanged) {
+ renderLight.impl = updateParameters.light;
+ renderLight.transition(transitionParameters);
+ }
+
+ if (lightChanged || zoomChanged || renderLight.hasTransition()) {
+ renderLight.evaluate(evaluationParameters);
+ }
+
+
+ const ImageDifference imageDiff = diffImages(imageImpls, updateParameters.images);
+ imageImpls = updateParameters.images;
+
+ // Remove removed images from sprite atlas.
+ for (const auto& entry : imageDiff.removed) {
+ imageManager->removeImage(entry.first);
+ }
+
+ // Add added images to sprite atlas.
+ for (const auto& entry : imageDiff.added) {
+ imageManager->addImage(entry.second);
+ }
+
+ // Update changed images.
+ for (const auto& entry : imageDiff.changed) {
+ imageManager->updateImage(entry.second.after);
+ }
+
+ imageManager->setLoaded(updateParameters.spriteLoaded);
+
+
+ const LayerDifference layerDiff = diffLayers(layerImpls, updateParameters.layers);
+ layerImpls = updateParameters.layers;
+
+ // Remove render layers for removed layers.
+ for (const auto& entry : layerDiff.removed) {
+ renderLayers.erase(entry.first);
+ }
+
+ // Create render layers for newly added layers.
+ for (const auto& entry : layerDiff.added) {
+ renderLayers.emplace(entry.first, RenderLayer::create(entry.second));
+ }
+
+ // Update render layers for changed layers.
+ for (const auto& entry : layerDiff.changed) {
+ renderLayers.at(entry.first)->setImpl(entry.second.after);
+ }
+
+ // Update layers for class and zoom changes.
+ for (const auto& entry : renderLayers) {
+ RenderLayer& layer = *entry.second;
+ const bool layerAdded = layerDiff.added.count(entry.first);
+ const bool layerChanged = layerDiff.changed.count(entry.first);
+
+ if (layerAdded || layerChanged) {
+ layer.transition(transitionParameters);
+ }
+
+ if (layerAdded || layerChanged || zoomChanged || layer.hasTransition()) {
+ layer.evaluate(evaluationParameters);
+ }
+ }
+
+
+ const SourceDifference sourceDiff = diffSources(sourceImpls, updateParameters.sources);
+ sourceImpls = updateParameters.sources;
+
+ // Remove render layers for removed sources.
+ for (const auto& entry : sourceDiff.removed) {
+ renderSources.erase(entry.first);
+ }
+
+ // Create render sources for newly added sources.
+ for (const auto& entry : sourceDiff.added) {
+ std::unique_ptr<RenderSource> renderSource = RenderSource::create(entry.second);
+ renderSource->setObserver(this);
+ renderSources.emplace(entry.first, std::move(renderSource));
+ }
+
+ const bool hasImageDiff = !(imageDiff.added.empty() && imageDiff.removed.empty() && imageDiff.changed.empty());
+
+ // Update all sources.
+ for (const auto& source : *sourceImpls) {
+ std::vector<Immutable<Layer::Impl>> filteredLayers;
+ bool needsRendering = false;
+ bool needsRelayout = false;
+
+ for (const auto& layer : *layerImpls) {
+ if (layer->type == LayerType::Background ||
+ layer->type == LayerType::Custom ||
+ layer->source != source->id) {
+ continue;
+ }
+
+ if (!needsRendering && getRenderLayer(layer->id)->needsRendering(zoomHistory.lastZoom)) {
+ needsRendering = true;
+ }
+
+ if (!needsRelayout && (hasImageDiff || hasLayoutDifference(layerDiff, layer->id))) {
+ needsRelayout = true;
+ }
+
+ filteredLayers.push_back(layer);
+ }
+
+ renderSources.at(source->id)->update(source,
+ filteredLayers,
+ needsRendering,
+ needsRelayout,
+ tileParameters);
+ }
+
+ transformState = updateParameters.transformState;
+
+ if (!staticData) {
+ staticData = std::make_unique<RenderStaticData>(backend.getContext(), pixelRatio, programCacheDir);
+ }
+
+ PaintParameters parameters {
+ backend.getContext(),
+ pixelRatio,
+ contextMode,
+ backend,
+ updateParameters,
+ renderLight.getEvaluated(),
+ *staticData,
+ frameHistory,
+ *imageManager,
+ *lineAtlas
+ };
+
+ bool loaded = updateParameters.styleLoaded && isLoaded();
+ if (updateParameters.mode == MapMode::Still && !loaded) {
+ return;
+ }
+
+ if (renderState == RenderState::Never) {
+ observer->onWillStartRenderingMap();
+ }
+
+ observer->onWillStartRenderingFrame();
+
+ backend.updateAssumedState();
+
+ if (parameters.contextMode == GLContextMode::Shared) {
+ parameters.context.setDirtyState();
+ }
+
+ Color backgroundColor;
+
+ class RenderItem {
+ public:
+ RenderLayer& layer;
+ RenderSource* source;
+ };
+
+ std::vector<RenderItem> order;
+
+ for (auto& layerImpl : *layerImpls) {
+ RenderLayer* layer = getRenderLayer(layerImpl->id);
+ assert(layer);
+
+ if (!parameters.staticData.has3D && layer->is<RenderFillExtrusionLayer>()) {
+ parameters.staticData.has3D = true;
+ }
+
+ if (!layer->needsRendering(zoomHistory.lastZoom)) {
+ continue;
+ }
+
+ if (const RenderBackgroundLayer* background = layer->as<RenderBackgroundLayer>()) {
+ const BackgroundPaintProperties::PossiblyEvaluated& paint = background->evaluated;
+ if (layerImpl.get() == layerImpls->at(0).get() && paint.get<BackgroundPattern>().from.empty()) {
+ // This is a solid background. We can use glClear().
+ backgroundColor = paint.get<BackgroundColor>() * paint.get<BackgroundOpacity>();
+ } else {
+ // This is a textured background, or not the bottommost layer. We need to render it with a quad.
+ order.emplace_back(RenderItem { *layer, nullptr });
+ }
+ continue;
+ }
+
+ if (layer->is<RenderCustomLayer>()) {
+ order.emplace_back(RenderItem { *layer, nullptr });
+ continue;
+ }
+
+ RenderSource* source = getRenderSource(layer->baseImpl->source);
+ if (!source) {
+ Log::Warning(Event::Render, "can't find source for layer '%s'", layer->getID().c_str());
+ continue;
+ }
+
+ const bool symbolLayer = layer->is<RenderSymbolLayer>();
+
+ auto sortedTiles = source->getRenderTiles();
+ if (symbolLayer) {
+ // Sort symbol tiles in opposite y position, so tiles with overlapping symbols are drawn
+ // on top of each other, with lower symbols being drawn on top of higher symbols.
+ std::sort(sortedTiles.begin(), sortedTiles.end(), [&](const RenderTile& a, const RenderTile& b) {
+ Point<float> pa(a.id.canonical.x, a.id.canonical.y);
+ Point<float> pb(b.id.canonical.x, b.id.canonical.y);
+
+ 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);
+ });
+ } else {
+ std::sort(sortedTiles.begin(), sortedTiles.end(),
+ [](const auto& a, const auto& b) { return a.get().id < b.get().id; });
+ }
+
+ std::vector<std::reference_wrapper<RenderTile>> sortedTilesForInsertion;
+ for (auto& sortedTile : sortedTiles) {
+ auto& tile = sortedTile.get();
+ if (!tile.tile.isRenderable()) {
+ 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;
+ }
+ }
+ layer->setRenderTiles(std::move(sortedTilesForInsertion));
+ order.emplace_back(RenderItem { *layer, source });
+ }
+
+ frameHistory.record(parameters.timePoint,
+ parameters.state.getZoom(),
+ parameters.mapMode == MapMode::Continuous ? util::DEFAULT_TRANSITION_DURATION : Milliseconds(0));
+
+ // - UPLOAD PASS -------------------------------------------------------------------------------
+ // Uploads all required buffers and images before we do any actual rendering.
+ {
+ MBGL_DEBUG_GROUP(parameters.context, "upload");
+
+ 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()) {
+ entry.second->startRender(parameters);
+ }
+ }
+ }
+
+ // - 3D PASS -------------------------------------------------------------------------------------
+ // Renders any 3D layers bottom-to-top to unique FBOs with texture attachments, but share the same
+ // depth rbo between them.
+ if (parameters.staticData.has3D) {
+ parameters.staticData.backendSize = parameters.backend.getFramebufferSize();
+
+ MBGL_DEBUG_GROUP(parameters.context, "3d");
+ parameters.pass = RenderPass::Pass3D;
+
+ if (!parameters.staticData.depthRenderbuffer ||
+ parameters.staticData.depthRenderbuffer->size != parameters.staticData.backendSize) {
+ parameters.staticData.depthRenderbuffer =
+ parameters.context.createRenderbuffer<gl::RenderbufferType::DepthComponent>(parameters.staticData.backendSize);
+ }
+ parameters.staticData.depthRenderbuffer->shouldClear(true);
+
+ uint32_t i = static_cast<uint32_t>(order.size()) - 1;
+ for (auto it = order.begin(); it != order.end(); ++it, --i) {
+ parameters.currentLayer = i;
+ if (it->layer.hasRenderPass(parameters.pass)) {
+ MBGL_DEBUG_GROUP(parameters.context, it->layer.getID());
+ it->layer.render(parameters, it->source);
+ }
+ }
+ }
+
+ // - CLEAR -------------------------------------------------------------------------------------
+ // Renders the backdrop of the OpenGL view. This also paints in areas where we don't have any
+ // tiles whatsoever.
+ {
+ MBGL_DEBUG_GROUP(parameters.context, "clear");
+ parameters.backend.bind();
+ parameters.context.clear((parameters.debugOptions & MapDebugOptions::Overdraw)
+ ? Color::black()
+ : backgroundColor,
+ 1.0f,
+ 0);
+ }
+
+ // - CLIPPING MASKS ----------------------------------------------------------------------------
+ // Draws the clipping masks to the stencil buffer.
+ {
+ MBGL_DEBUG_GROUP(parameters.context, "clipping masks");
+
+ static const style::FillPaintProperties::PossiblyEvaluated properties {};
+ static const FillProgram::PaintPropertyBinders paintAttibuteData(properties, 0);
+
+ for (const auto& clipID : parameters.clipIDGenerator.getClipIDs()) {
+ parameters.staticData.programs.fill.get(properties).draw(
+ parameters.context,
+ gl::Triangles(),
+ gl::DepthMode::disabled(),
+ gl::StencilMode {
+ gl::StencilMode::Always(),
+ static_cast<int32_t>(clipID.second.reference.to_ulong()),
+ 0b11111111,
+ gl::StencilMode::Keep,
+ gl::StencilMode::Keep,
+ gl::StencilMode::Replace
+ },
+ gl::ColorMode::disabled(),
+ FillProgram::UniformValues {
+ uniforms::u_matrix::Value{ parameters.matrixForTile(clipID.first) },
+ uniforms::u_world::Value{ parameters.context.viewport.getCurrentValue().size },
+ },
+ parameters.staticData.tileVertexBuffer,
+ parameters.staticData.quadTriangleIndexBuffer,
+ parameters.staticData.tileTriangleSegments,
+ paintAttibuteData,
+ properties,
+ parameters.state.getZoom(),
+ "clipping"
+ );
+ }
+ }
+
+#if not MBGL_USE_GLES2 and not defined(NDEBUG)
+ // Render tile clip boundaries, using stencil buffer to calculate fill color.
+ if (parameters.debugOptions & MapDebugOptions::StencilClip) {
+ parameters.context.setStencilMode(gl::StencilMode::disabled());
+ parameters.context.setDepthMode(gl::DepthMode::disabled());
+ parameters.context.setColorMode(gl::ColorMode::unblended());
+ parameters.context.program = 0;
+
+ // Reset the value in case someone else changed it, or it's dirty.
+ parameters.context.pixelTransferStencil = gl::value::PixelTransferStencil::Default;
+
+ // Read the stencil buffer
+ const auto viewport = parameters.context.viewport.getCurrentValue();
+ auto image = parameters.context.readFramebuffer<AlphaImage, gl::TextureFormat::Stencil>(viewport.size, false);
+
+ // Scale the Stencil buffer to cover the entire color space.
+ auto it = image.data.get();
+ auto end = it + viewport.size.width * viewport.size.height;
+ const auto factor = 255.0f / *std::max_element(it, end);
+ for (; it != end; ++it) {
+ *it *= factor;
+ }
+
+ parameters.context.pixelZoom = { 1, 1 };
+ parameters.context.rasterPos = { -1, -1, 0, 1 };
+ parameters.context.drawPixels(image);
+
+ return;
+ }
+#endif
+
+ // Actually render the layers
+
+ parameters.depthRangeSize = 1 - (order.size() + 2) * parameters.numSublayers * parameters.depthEpsilon;
+
+ // - OPAQUE PASS -------------------------------------------------------------------------------
+ // Render everything top-to-bottom by using reverse iterators. Render opaque objects first.
+ {
+ parameters.pass = RenderPass::Opaque;
+ MBGL_DEBUG_GROUP(parameters.context, "opaque");
+
+ uint32_t i = 0;
+ for (auto it = order.rbegin(); it != order.rend(); ++it, ++i) {
+ parameters.currentLayer = i;
+ if (it->layer.hasRenderPass(parameters.pass)) {
+ MBGL_DEBUG_GROUP(parameters.context, it->layer.getID());
+ it->layer.render(parameters, it->source);
+ }
+ }
+ }
+
+ // - TRANSLUCENT PASS --------------------------------------------------------------------------
+ // Make a second pass, rendering translucent objects. This time, we render bottom-to-top.
+ {
+ parameters.pass = RenderPass::Translucent;
+ MBGL_DEBUG_GROUP(parameters.context, "translucent");
+
+ uint32_t i = static_cast<uint32_t>(order.size()) - 1;
+ for (auto it = order.begin(); it != order.end(); ++it, --i) {
+ parameters.currentLayer = i;
+ if (it->layer.hasRenderPass(parameters.pass)) {
+ MBGL_DEBUG_GROUP(parameters.context, it->layer.getID());
+ it->layer.render(parameters, it->source);
+ }
+ }
+ }
+
+ // - DEBUG PASS --------------------------------------------------------------------------------
+ // Renders debug overlays.
+ {
+ MBGL_DEBUG_GROUP(parameters.context, "debug");
+
+ // Finalize the rendering, e.g. by calling debug render calls per tile.
+ // This guarantees that we have at least one function per tile called.
+ // When only rendering layers via the stylesheet, it's possible that we don't
+ // ever visit a tile during rendering.
+ for (const auto& entry : renderSources) {
+ if (entry.second->isEnabled()) {
+ entry.second->finishRender(parameters);
+ }
+ }
+ }
+
+#if not MBGL_USE_GLES2 and not defined(NDEBUG)
+ // Render the depth buffer.
+ if (parameters.debugOptions & MapDebugOptions::DepthBuffer) {
+ parameters.context.setStencilMode(gl::StencilMode::disabled());
+ parameters.context.setDepthMode(gl::DepthMode::disabled());
+ parameters.context.setColorMode(gl::ColorMode::unblended());
+ parameters.context.program = 0;
+
+ // Scales the values in the depth buffer so that they cover the entire grayscale range. This
+ // makes it easier to spot tiny differences.
+ const float base = 1.0f / (1.0f - parameters.depthRangeSize);
+ parameters.context.pixelTransferDepth = { base, 1.0f - base };
+
+ // Read the stencil buffer
+ auto viewport = parameters.context.viewport.getCurrentValue();
+ auto image = parameters.context.readFramebuffer<AlphaImage, gl::TextureFormat::Depth>(viewport.size, false);
+
+ parameters.context.pixelZoom = { 1, 1 };
+ parameters.context.rasterPos = { -1, -1, 0, 1 };
+ parameters.context.drawPixels(image);
+ }
+#endif
+
+ // TODO: Find a better way to unbind VAOs after we're done with them without introducing
+ // unnecessary bind(0)/bind(N) sequences.
+ {
+ MBGL_DEBUG_GROUP(parameters.context, "cleanup");
+
+ parameters.context.activeTextureUnit = 1;
+ parameters.context.texture[1] = 0;
+ parameters.context.activeTextureUnit = 0;
+ parameters.context.texture[0] = 0;
+
+ parameters.context.bindVertexArray = 0;
+ }
+
+ observer->onDidFinishRenderingFrame(
+ loaded ? RendererObserver::RenderMode::Full : RendererObserver::RenderMode::Partial,
+ updateParameters.mode == MapMode::Continuous && (hasTransitions() || frameHistory.needsAnimation(util::DEFAULT_TRANSITION_DURATION))
+ );
+
+ if (!loaded) {
+ renderState = RenderState::Partial;
+ } else if (renderState != RenderState::Fully) {
+ renderState = RenderState::Fully;
+ observer->onDidFinishRenderingMap();
+ }
+
+ // Cleanup only after signaling completion
+ parameters.context.performCleanup();
+}
+
+std::vector<Feature> Renderer::Impl::queryRenderedFeatures(const ScreenLineString& geometry, const RenderedQueryOptions& options) const {
+ std::vector<const RenderLayer*> layers;
+ if (options.layerIDs) {
+ for (const auto& layerID : *options.layerIDs) {
+ if (const RenderLayer* layer = getRenderLayer(layerID)) {
+ layers.emplace_back(layer);
+ }
+ }
+ } else {
+ for (const auto& entry : renderLayers) {
+ layers.emplace_back(entry.second.get());
+ }
+ }
+
+ std::unordered_set<std::string> sourceIDs;
+ for (const RenderLayer* layer : layers) {
+ sourceIDs.emplace(layer->baseImpl->source);
+ }
+
+ 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);
+ std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin()));
+ }
+ }
+
+ std::vector<Feature> result;
+
+ if (resultsByLayer.empty()) {
+ return result;
+ }
+
+ // Combine all results based on the style layer order.
+ for (const auto& layerImpl : *layerImpls) {
+ const RenderLayer* layer = getRenderLayer(layerImpl->id);
+ if (!layer->needsRendering(zoomHistory.lastZoom)) {
+ continue;
+ }
+ auto it = resultsByLayer.find(layer->baseImpl->id);
+ if (it != resultsByLayer.end()) {
+ std::move(it->second.begin(), it->second.end(), std::back_inserter(result));
+ }
+ }
+
+ return result;
+}
+
+std::vector<Feature> Renderer::Impl::querySourceFeatures(const std::string& sourceID, const SourceQueryOptions& options) const {
+ const RenderSource* source = getRenderSource(sourceID);
+ if (!source) return {};
+
+ return source->querySourceFeatures(options);
+}
+
+void Renderer::Impl::onLowMemory() {
+ assert(BackendScope::exists());
+ backend.getContext().performCleanup();
+ for (const auto& entry : renderSources) {
+ entry.second->onLowMemory();
+ }
+ observer->onInvalidate();
+}
+
+void Renderer::Impl::dumDebugLogs() {
+ for (const auto& entry : renderSources) {
+ entry.second->dumpDebugLogs();
+ }
+
+ imageManager->dumpDebugLogs();
+}
+
+RenderLayer* Renderer::Impl::getRenderLayer(const std::string& id) {
+ auto it = renderLayers.find(id);
+ return it != renderLayers.end() ? it->second.get() : nullptr;
+}
+
+const RenderLayer* Renderer::Impl::getRenderLayer(const std::string& id) const {
+ auto it = renderLayers.find(id);
+ return it != renderLayers.end() ? it->second.get() : nullptr;
+}
+
+RenderSource* Renderer::Impl::getRenderSource(const std::string& id) const {
+ auto it = renderSources.find(id);
+ return it != renderSources.end() ? it->second.get() : nullptr;
+}
+
+bool Renderer::Impl::hasTransitions() const {
+ if (renderLight.hasTransition()) {
+ return true;
+ }
+
+ for (const auto& entry : renderLayers) {
+ if (entry.second->hasTransition()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool Renderer::Impl::isLoaded() const {
+ for (const auto& entry: renderSources) {
+ if (!entry.second->isLoaded()) {
+ return false;
+ }
+ }
+
+ if (!imageManager->isLoaded()) {
+ return false;
+ }
+
+ return true;
+}
+
+void Renderer::Impl::onGlyphsError(const FontStack& fontStack, const GlyphRange& glyphRange, std::exception_ptr error) {
+ Log::Error(Event::Style, "Failed to load glyph range %d-%d for font stack %s: %s",
+ glyphRange.first, glyphRange.second, fontStackToString(fontStack).c_str(), util::toString(error).c_str());
+ observer->onResourceError(error);
+}
+
+void Renderer::Impl::onTileError(RenderSource& source, const OverscaledTileID& tileID, std::exception_ptr error) {
+ Log::Error(Event::Style, "Failed to load tile %s for source %s: %s",
+ util::toString(tileID).c_str(), source.baseImpl->id.c_str(), util::toString(error).c_str());
+ observer->onResourceError(error);
+}
+
+void Renderer::Impl::onTileChanged(RenderSource&, const OverscaledTileID&) {
+ observer->onInvalidate();
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/renderer_impl.hpp b/src/mbgl/renderer/renderer_impl.hpp
new file mode 100644
index 0000000000..30e7f70722
--- /dev/null
+++ b/src/mbgl/renderer/renderer_impl.hpp
@@ -0,0 +1,111 @@
+#pragma once
+
+#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/map/mode.hpp>
+#include <mbgl/text/glyph_manager_observer.hpp>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace mbgl {
+
+class RendererBackend;
+class RendererObserver;
+class RenderSource;
+class RenderLayer;
+class UpdateParameters;
+class RenderStaticData;
+class RenderedQueryOptions;
+class SourceQueryOptions;
+class FileSource;
+class Scheduler;
+class GlyphManager;
+class ImageManager;
+class LineAtlas;
+
+class Renderer::Impl : public GlyphManagerObserver,
+ public RenderSourceObserver{
+public:
+ Impl(RendererBackend&, float pixelRatio_, FileSource&, Scheduler&, GLContextMode,
+ const optional<std::string> programCacheDir);
+ ~Impl() final;
+
+ void markContextLost() {
+ contextLost = true;
+ };
+
+ void setObserver(RendererObserver*);
+
+ void render(const UpdateParameters&);
+
+ std::vector<Feature> queryRenderedFeatures(const ScreenLineString&, const RenderedQueryOptions&) const;
+ std::vector<Feature> querySourceFeatures(const std::string& sourceID, const SourceQueryOptions&) const;
+
+ void onLowMemory();
+ void dumDebugLogs();
+
+private:
+ bool isLoaded() const;
+ bool hasTransitions() const;
+
+ RenderSource* getRenderSource(const std::string& id) const;
+
+ RenderLayer* getRenderLayer(const std::string& id);
+ const RenderLayer* getRenderLayer(const std::string& id) const;
+
+ // GlyphManagerObserver implementation.
+ void onGlyphsError(const FontStack&, const GlyphRange&, std::exception_ptr) override;
+
+ // RenderSourceObserver implementation.
+ void onTileChanged(RenderSource&, const OverscaledTileID&) override;
+ void onTileError(RenderSource&, const OverscaledTileID&, std::exception_ptr) override;
+
+ friend class Renderer;
+
+ RendererBackend& backend;
+ Scheduler& scheduler;
+ FileSource& fileSource;
+
+ RendererObserver* observer;
+
+ const GLContextMode contextMode;
+ const float pixelRatio;
+ const optional<std::string> programCacheDir;
+
+ enum class RenderState {
+ Never,
+ Partial,
+ Fully,
+ };
+
+ RenderState renderState = RenderState::Never;
+ FrameHistory frameHistory;
+ ZoomHistory zoomHistory;
+ TransformState transformState;
+
+ std::unique_ptr<GlyphManager> glyphManager;
+ std::unique_ptr<ImageManager> imageManager;
+ std::unique_ptr<LineAtlas> lineAtlas;
+ std::unique_ptr<RenderStaticData> staticData;
+
+ Immutable<std::vector<Immutable<style::Image::Impl>>> imageImpls;
+ Immutable<std::vector<Immutable<style::Source::Impl>>> sourceImpls;
+ Immutable<std::vector<Immutable<style::Layer::Impl>>> layerImpls;
+
+ std::unordered_map<std::string, std::unique_ptr<RenderSource>> renderSources;
+ std::unordered_map<std::string, std::unique_ptr<RenderLayer>> renderLayers;
+ RenderLight renderLight;
+
+ bool contextLost = false;
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/renderer_observer.hpp b/src/mbgl/renderer/renderer_observer.hpp
new file mode 100644
index 0000000000..551b5c803e
--- /dev/null
+++ b/src/mbgl/renderer/renderer_observer.hpp
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <exception>
+
+namespace mbgl {
+
+class RendererObserver {
+public:
+ virtual ~RendererObserver() = default;
+
+ enum class RenderMode : uint32_t {
+ Partial,
+ Full
+ };
+
+ // Signals that a repaint is required
+ virtual void onInvalidate() {}
+
+ // Resource failed to download / parse
+ virtual void onResourceError(std::exception_ptr) {}
+
+ // First frame
+ virtual void onWillStartRenderingMap() {}
+
+ // Start of frame, initial is the first frame for this map
+ virtual void onWillStartRenderingFrame() {}
+
+ // End of frame, boolean flags that a repaint is required
+ virtual void onDidFinishRenderingFrame(RenderMode, bool) {}
+
+ // Final frame
+ virtual void onDidFinishRenderingMap() {}
+};
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/sources/render_geojson_source.cpp b/src/mbgl/renderer/sources/render_geojson_source.cpp
index 2b1eeea73b..504db78ea3 100644
--- a/src/mbgl/renderer/sources/render_geojson_source.cpp
+++ b/src/mbgl/renderer/sources/render_geojson_source.cpp
@@ -1,6 +1,8 @@
#include <mbgl/renderer/sources/render_geojson_source.hpp>
#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/tile/geojson_tile.hpp>
+#include <mbgl/renderer/tile_parameters.hpp>
#include <mbgl/algorithm/generate_clip_ids.hpp>
#include <mbgl/algorithm/generate_clip_ids_impl.hpp>
@@ -9,81 +11,87 @@ namespace mbgl {
using namespace style;
-RenderGeoJSONSource::RenderGeoJSONSource(const style::GeoJSONSource::Impl& impl_)
- : RenderSource(impl_),
- impl(impl_) {
+RenderGeoJSONSource::RenderGeoJSONSource(Immutable<style::GeoJSONSource::Impl> impl_)
+ : RenderSource(impl_) {
tilePyramid.setObserver(this);
}
-bool RenderGeoJSONSource::isLoaded() const {
- return tilePyramid.isLoaded();
-}
-
-void RenderGeoJSONSource::invalidateTiles() {
- tilePyramid.invalidateTiles();
-}
-
-void RenderGeoJSONSource::startRender(algorithm::ClipIDGenerator& generator, const mat4& projMatrix, const mat4& clipMatrix, const TransformState& transform) {
- generator.update(tilePyramid.getRenderTiles());
- tilePyramid.startRender(projMatrix, clipMatrix, transform);
+const style::GeoJSONSource::Impl& RenderGeoJSONSource::impl() const {
+ return static_cast<const style::GeoJSONSource::Impl&>(*baseImpl);
}
-void RenderGeoJSONSource::finishRender(Painter& painter) {
- tilePyramid.finishRender(painter);
+bool RenderGeoJSONSource::isLoaded() const {
+ return tilePyramid.isLoaded();
}
-std::map<UnwrappedTileID, RenderTile>& RenderGeoJSONSource::getRenderTiles() {
- return tilePyramid.getRenderTiles();
-}
+void RenderGeoJSONSource::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_);
-void RenderGeoJSONSource::updateTiles(const TileParameters& parameters) {
- GeoJSONData* data_ = impl.getData();
+ enabled = needsRendering;
- if (!data_) {
- return;
- }
+ GeoJSONData* data_ = impl().getData();
if (data_ != data) {
data = data_;
tilePyramid.cache.clear();
- for (auto const& item : tilePyramid.tiles) {
- static_cast<GeoJSONTile*>(item.second.get())->updateData(data->getTile(item.first.canonical));
+ if (data) {
+ const uint8_t maxZ = impl().getZoomRange().max;
+ for (const auto& pair : tilePyramid.tiles) {
+ if (pair.first.canonical.z <= maxZ) {
+ static_cast<GeoJSONTile*>(pair.second.get())->updateData(data->getTile(pair.first.canonical));
+ }
+ }
}
}
- tilePyramid.updateTiles(parameters,
- SourceType::GeoJSON,
- util::tileSize,
- impl.getZoomRange(),
- [&] (const OverscaledTileID& tileID) {
- return std::make_unique<GeoJSONTile>(tileID, impl.id, parameters, data->getTile(tileID.canonical));
- });
+ if (!data) {
+ tilePyramid.tiles.clear();
+ tilePyramid.renderTiles.clear();
+ return;
+ }
+
+ tilePyramid.update(layers,
+ needsRendering,
+ needsRelayout,
+ parameters,
+ SourceType::GeoJSON,
+ util::tileSize,
+ impl().getZoomRange(),
+ [&] (const OverscaledTileID& tileID) {
+ return std::make_unique<GeoJSONTile>(tileID, impl().id, parameters, data->getTile(tileID.canonical));
+ });
}
-void RenderGeoJSONSource::removeTiles() {
- tilePyramid.removeTiles();
+void RenderGeoJSONSource::startRender(PaintParameters& parameters) {
+ parameters.clipIDGenerator.update(tilePyramid.getRenderTiles());
+ tilePyramid.startRender(parameters);
}
-void RenderGeoJSONSource::reloadTiles() {
- tilePyramid.reloadTiles();
+void RenderGeoJSONSource::finishRender(PaintParameters& parameters) {
+ tilePyramid.finishRender(parameters);
+}
+
+std::vector<std::reference_wrapper<RenderTile>> RenderGeoJSONSource::getRenderTiles() {
+ return tilePyramid.getRenderTiles();
}
std::unordered_map<std::string, std::vector<Feature>>
RenderGeoJSONSource::queryRenderedFeatures(const ScreenLineString& geometry,
- const TransformState& transformState,
- const RenderedQueryOptions& options) const {
- return tilePyramid.queryRenderedFeatures(geometry, transformState, options);
+ const TransformState& transformState,
+ const std::vector<const RenderLayer*>& layers,
+ const RenderedQueryOptions& options) const {
+ return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options);
}
std::vector<Feature> RenderGeoJSONSource::querySourceFeatures(const SourceQueryOptions& options) const {
return tilePyramid.querySourceFeatures(options);
}
-void RenderGeoJSONSource::setCacheSize(size_t size) {
- tilePyramid.setCacheSize(size);
-}
-
void RenderGeoJSONSource::onLowMemory() {
tilePyramid.onLowMemory();
}
diff --git a/src/mbgl/renderer/sources/render_geojson_source.hpp b/src/mbgl/renderer/sources/render_geojson_source.hpp
index 262ab29276..72ab4879ef 100644
--- a/src/mbgl/renderer/sources/render_geojson_source.hpp
+++ b/src/mbgl/renderer/sources/render_geojson_source.hpp
@@ -12,48 +12,43 @@ class GeoJSONData;
class RenderGeoJSONSource : public RenderSource {
public:
- RenderGeoJSONSource(const style::GeoJSONSource::Impl&);
+ RenderGeoJSONSource(Immutable<style::GeoJSONSource::Impl>);
bool isLoaded() const final;
- // Called when the camera has changed. May load new tiles, unload obsolete tiles, or
- // trigger re-placement of existing complete tiles.
- void updateTiles(const TileParameters&) final;
+ void update(Immutable<style::Source::Impl>,
+ const std::vector<Immutable<style::Layer::Impl>>&,
+ bool needsRendering,
+ bool needsRelayout,
+ const TileParameters&) final;
- // Removes all tiles (by putting them into the cache).
- void removeTiles() final;
+ void startRender(PaintParameters&) final;
+ void finishRender(PaintParameters&) final;
- // Remove all tiles and clear the cache.
- void invalidateTiles() final;
-
- // Request that all loaded tiles re-run the layout operation on the existing source
- // data with fresh style information.
- void reloadTiles() final;
-
- void startRender(algorithm::ClipIDGenerator&,
- const mat4& projMatrix,
- const mat4& clipMatrix,
- const TransformState&) final;
- void finishRender(Painter&) final;
-
- std::map<UnwrappedTileID, RenderTile>& getRenderTiles() 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 final;
std::vector<Feature>
querySourceFeatures(const SourceQueryOptions&) const final;
- void setCacheSize(size_t) final;
void onLowMemory() final;
void dumpDebugLogs() const final;
private:
- const style::GeoJSONSource::Impl& impl;
+ const style::GeoJSONSource::Impl& impl() const;
+
TilePyramid tilePyramid;
- style::GeoJSONData* data;
+ style::GeoJSONData* data = nullptr;
};
+template <>
+inline bool RenderSource::is<RenderGeoJSONSource>() const {
+ return baseImpl->type == SourceType::GeoJSON;
+}
+
} // namespace mbgl
diff --git a/src/mbgl/renderer/sources/render_image_source.cpp b/src/mbgl/renderer/sources/render_image_source.cpp
new file mode 100644
index 0000000000..9140e01711
--- /dev/null
+++ b/src/mbgl/renderer/sources/render_image_source.cpp
@@ -0,0 +1,214 @@
+#include <mbgl/map/transform_state.hpp>
+#include <mbgl/math/log2.hpp>
+#include <mbgl/renderer/buckets/raster_bucket.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/sources/render_image_source.hpp>
+#include <mbgl/renderer/tile_parameters.hpp>
+#include <mbgl/renderer/render_static_data.hpp>
+#include <mbgl/programs/programs.hpp>
+#include <mbgl/util/tile_coordinate.hpp>
+#include <mbgl/util/tile_cover.hpp>
+#include <mbgl/util/logging.hpp>
+#include <mbgl/util/constants.hpp>
+
+namespace mbgl {
+
+using namespace style;
+
+RenderImageSource::RenderImageSource(Immutable<style::ImageSource::Impl> impl_)
+ : RenderSource(impl_) {
+}
+
+RenderImageSource::~RenderImageSource() = default;
+
+const style::ImageSource::Impl& RenderImageSource::impl() const {
+ return static_cast<const style::ImageSource::Impl&>(*baseImpl);
+}
+
+bool RenderImageSource::isLoaded() const {
+ return !!bucket;
+}
+
+void RenderImageSource::startRender(PaintParameters& parameters) {
+ if (!isLoaded()) {
+ return;
+ }
+
+ matrices.clear();
+
+ for (size_t i = 0; i < tileIds.size(); i++) {
+ mat4 matrix;
+ matrix::identity(matrix);
+ parameters.state.matrixFor(matrix, tileIds[i]);
+ matrix::multiply(matrix, parameters.projMatrix, matrix);
+ matrices.push_back(matrix);
+ }
+
+ if (bucket->needsUpload()) {
+ bucket->upload(parameters.context);
+ }
+}
+
+void RenderImageSource::finishRender(PaintParameters& parameters) {
+ if (!isLoaded() || !(parameters.debugOptions & MapDebugOptions::TileBorders)) {
+ return;
+ }
+
+ static const style::Properties<>::PossiblyEvaluated properties {};
+ static const DebugProgram::PaintPropertyBinders paintAttibuteData(properties, 0);
+
+ for (auto matrix : matrices) {
+ parameters.programs.debug.draw(
+ parameters.context,
+ gl::LineStrip { 4.0f * parameters.pixelRatio },
+ gl::DepthMode::disabled(),
+ gl::StencilMode::disabled(),
+ gl::ColorMode::unblended(),
+ DebugProgram::UniformValues {
+ uniforms::u_matrix::Value{ matrix },
+ uniforms::u_color::Value{ Color::red() }
+ },
+ parameters.staticData.tileVertexBuffer,
+ parameters.staticData.tileBorderIndexBuffer,
+ parameters.staticData.tileBorderSegments,
+ paintAttibuteData,
+ properties,
+ parameters.state.getZoom(),
+ "debug"
+ );
+ }
+}
+
+std::unordered_map<std::string, std::vector<Feature>>
+RenderImageSource::queryRenderedFeatures(const ScreenLineString&,
+ const TransformState&,
+ const std::vector<const RenderLayer*>&,
+ const RenderedQueryOptions&) const {
+ return std::unordered_map<std::string, std::vector<Feature>> {};
+}
+
+std::vector<Feature> RenderImageSource::querySourceFeatures(const SourceQueryOptions&) const {
+ return {};
+}
+
+void RenderImageSource::update(Immutable<style::Source::Impl> baseImpl_,
+ const std::vector<Immutable<Layer::Impl>>&,
+ const bool needsRendering,
+ const bool,
+ const TileParameters& parameters) {
+ enabled = needsRendering;
+ if (!needsRendering) {
+ return;
+ }
+
+ auto transformState = parameters.transformState;
+ std::swap(baseImpl, baseImpl_);
+
+ auto coords = impl().getCoordinates();
+ std::shared_ptr<PremultipliedImage> image = impl().getImage();
+
+ if (!image || !image->valid()) {
+ enabled = false;
+ return;
+ }
+
+ auto size = transformState.getSize();
+ const double viewportHeight = size.height;
+
+ // Compute the screen coordinates at wrap=0 for the given LatLng
+ ScreenCoordinate nePixel = { -INFINITY, -INFINITY };
+ ScreenCoordinate swPixel = { INFINITY, INFINITY };
+
+ for (LatLng latLng : coords) {
+ ScreenCoordinate pixel = transformState.latLngToScreenCoordinate(latLng);
+ swPixel.x = std::min(swPixel.x, pixel.x);
+ nePixel.x = std::max(nePixel.x, pixel.x);
+ swPixel.y = std::min(swPixel.y, viewportHeight - pixel.y);
+ nePixel.y = std::max(nePixel.y, viewportHeight - pixel.y);
+ }
+ const double width = nePixel.x - swPixel.x;
+ const double height = nePixel.y - swPixel.y;
+
+ // Don't bother drawing the ImageSource unless it occupies >4 screen pixels
+ enabled = (width * height > 4);
+ if (!enabled) {
+ return;
+ }
+
+ // Calculate the optimum zoom level to determine the tile ids to use for transforms
+ double minScale = INFINITY;
+ double scaleX = double(size.width) / width;
+ double scaleY = double(size.height) / height;
+ minScale = util::min(scaleX, scaleY);
+ double zoom = transformState.getZoom() + util::log2(minScale);
+ zoom = std::floor(util::clamp(zoom, transformState.getMinZoom(), transformState.getMaxZoom()));
+ auto imageBounds = LatLngBounds::hull(coords[0], coords[1]);
+ imageBounds.extend(coords[2]);
+ imageBounds.extend(coords[3]);
+ auto tileCover = util::tileCover(imageBounds, zoom);
+ tileIds.clear();
+ tileIds.push_back(tileCover[0]);
+ bool hasVisibleTile = false;
+
+ // Add additional wrapped tile ids if neccessary
+ auto idealTiles = util::tileCover(transformState, transformState.getZoom());
+ for (auto tile : idealTiles) {
+ if (tile.wrap != 0 && tileCover[0].canonical.isChildOf(tile.canonical)) {
+ tileIds.push_back({ tile.wrap, tileCover[0].canonical });
+ hasVisibleTile = true;
+ }
+ else if (!hasVisibleTile) {
+ for (auto coveringTile: tileCover) {
+ if(coveringTile.canonical == tile.canonical ||
+ coveringTile.canonical.isChildOf(tile.canonical) ||
+ tile.canonical.isChildOf(coveringTile.canonical)) {
+ hasVisibleTile = true;
+ }
+ }
+ }
+ }
+
+ enabled = hasVisibleTile;
+ if (!enabled) {
+ return;
+ }
+
+ // Calculate Geometry Coordinates based on tile cover at ideal zoom
+ GeometryCoordinates geomCoords;
+ for (auto latLng : coords) {
+ auto tc = TileCoordinate::fromLatLng(0, latLng);
+ auto gc = TileCoordinate::toGeometryCoordinate(tileIds[0], tc.p);
+ geomCoords.push_back(gc);
+ }
+ if (!bucket) {
+ bucket = std::make_unique<RasterBucket>(image);
+ } else {
+ bucket->clear();
+ if (image != bucket->image) {
+ bucket->setImage(image);
+ }
+ }
+
+ // Set Bucket Vertices, Indices, and segments
+ bucket->vertices.emplace_back(
+ RasterProgram::layoutVertex({ geomCoords[0].x, geomCoords[0].y }, { 0, 0 }));
+ bucket->vertices.emplace_back(
+ RasterProgram::layoutVertex({ geomCoords[1].x, geomCoords[1].y }, { util::EXTENT, 0 }));
+ bucket->vertices.emplace_back(
+ RasterProgram::layoutVertex({ geomCoords[3].x, geomCoords[3].y }, { 0, util::EXTENT }));
+ bucket->vertices.emplace_back(
+ RasterProgram::layoutVertex({ geomCoords[2].x, geomCoords[2].y }, { util::EXTENT, util::EXTENT }));
+
+ bucket->indices.emplace_back(0, 1, 2);
+ bucket->indices.emplace_back(1, 2, 3);
+
+ bucket->segments.emplace_back(0, 0, 4, 6);
+}
+
+void RenderImageSource::dumpDebugLogs() const {
+ Log::Info(Event::General, "RenderImageSource::id: %s", impl().id.c_str());
+ Log::Info(Event::General, "RenderImageSource::loaded: %s", isLoaded() ? "yes" : "no");
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/sources/render_image_source.hpp b/src/mbgl/renderer/sources/render_image_source.hpp
new file mode 100644
index 0000000000..7b69d09fa7
--- /dev/null
+++ b/src/mbgl/renderer/sources/render_image_source.hpp
@@ -0,0 +1,58 @@
+#pragma once
+
+#include <mbgl/renderer/render_source.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/style/sources/image_source_impl.hpp>
+
+namespace mbgl {
+
+class RasterBucket;
+
+class RenderImageSource : public RenderSource {
+public:
+ RenderImageSource(Immutable<style::ImageSource::Impl>);
+ ~RenderImageSource() override;
+
+ bool isLoaded() const final;
+
+ void startRender(PaintParameters&) final;
+ void finishRender(PaintParameters&) final;
+
+ void update(Immutable<style::Source::Impl>,
+ const std::vector<Immutable<style::Layer::Impl>>&,
+ bool needsRendering,
+ bool needsRelayout,
+ const TileParameters&) final;
+
+ std::vector<std::reference_wrapper<RenderTile>> getRenderTiles() final {
+ return {};
+ }
+
+ 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 final;
+
+ std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const final;
+
+ void onLowMemory() final {
+ }
+ void dumpDebugLogs() const final;
+
+private:
+ friend class RenderRasterLayer;
+
+ const style::ImageSource::Impl& impl() const;
+
+ std::vector<UnwrappedTileID> tileIds;
+ std::unique_ptr<RasterBucket> bucket;
+ std::vector<mat4> matrices;
+};
+
+template <>
+inline bool RenderSource::is<RenderImageSource>() const {
+ return baseImpl->type == SourceType::Image;
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/sources/render_raster_source.cpp b/src/mbgl/renderer/sources/render_raster_source.cpp
index c5a29eebf5..bcd719365d 100644
--- a/src/mbgl/renderer/sources/render_raster_source.cpp
+++ b/src/mbgl/renderer/sources/render_raster_source.cpp
@@ -1,39 +1,35 @@
#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 {
using namespace style;
-RenderRasterSource::RenderRasterSource(const style::RasterSource::Impl& impl_)
- : RenderSource(impl_),
- impl(impl_) {
+RenderRasterSource::RenderRasterSource(Immutable<style::RasterSource::Impl> impl_)
+ : RenderSource(impl_) {
tilePyramid.setObserver(this);
}
-bool RenderRasterSource::isLoaded() const {
- return tilePyramid.isLoaded();
-}
-
-void RenderRasterSource::invalidateTiles() {
- tilePyramid.invalidateTiles();
+const style::RasterSource::Impl& RenderRasterSource::impl() const {
+ return static_cast<const style::RasterSource::Impl&>(*baseImpl);
}
-void RenderRasterSource::startRender(algorithm::ClipIDGenerator&, const mat4& projMatrix, const mat4& clipMatrix, const TransformState& transform) {
- tilePyramid.startRender(projMatrix, clipMatrix, transform);
+bool RenderRasterSource::isLoaded() const {
+ return tilePyramid.isLoaded();
}
-void RenderRasterSource::finishRender(Painter& painter) {
- tilePyramid.finishRender(painter);
-}
+void RenderRasterSource::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_);
-std::map<UnwrappedTileID, RenderTile>& RenderRasterSource::getRenderTiles() {
- return tilePyramid.getRenderTiles();
-}
+ enabled = needsRendering;
-void RenderRasterSource::updateTiles(const TileParameters& parameters) {
- optional<Tileset> tileset = impl.getTileset();
+ optional<Tileset> tileset = impl().getTileset();
if (!tileset) {
return;
@@ -41,41 +37,51 @@ void RenderRasterSource::updateTiles(const TileParameters& parameters) {
if (tileURLTemplates != tileset->tiles) {
tileURLTemplates = tileset->tiles;
- tilePyramid.invalidateTiles();
+
+ // TODO: this removes existing buckets, and will cause flickering.
+ // Should instead refresh tile data in place.
+ tilePyramid.tiles.clear();
+ tilePyramid.renderTiles.clear();
+ tilePyramid.cache.clear();
}
- tilePyramid.updateTiles(parameters,
- SourceType::Raster,
- impl.getTileSize(),
- tileset->zoomRange,
- [&] (const OverscaledTileID& tileID) {
- return std::make_unique<RasterTile>(tileID, parameters, *tileset);
- });
+ tilePyramid.update(layers,
+ needsRendering,
+ needsRelayout,
+ parameters,
+ SourceType::Raster,
+ impl().getTileSize(),
+ tileset->zoomRange,
+ [&] (const OverscaledTileID& tileID) {
+ return std::make_unique<RasterTile>(tileID, parameters, *tileset);
+ });
+}
+
+void RenderRasterSource::startRender(PaintParameters& parameters) {
+ algorithm::updateTileMasks(tilePyramid.getRenderTiles());
+ tilePyramid.startRender(parameters);
}
-void RenderRasterSource::removeTiles() {
- tilePyramid.removeTiles();
+void RenderRasterSource::finishRender(PaintParameters& parameters) {
+ tilePyramid.finishRender(parameters);
}
-void RenderRasterSource::reloadTiles() {
- tilePyramid.reloadTiles();
+std::vector<std::reference_wrapper<RenderTile>> RenderRasterSource::getRenderTiles() {
+ return tilePyramid.getRenderTiles();
}
std::unordered_map<std::string, std::vector<Feature>>
RenderRasterSource::queryRenderedFeatures(const ScreenLineString&,
const TransformState&,
+ const std::vector<const RenderLayer*>&,
const RenderedQueryOptions&) const {
- return {};
+ return std::unordered_map<std::string, std::vector<Feature>> {};
}
std::vector<Feature> RenderRasterSource::querySourceFeatures(const SourceQueryOptions&) const {
return {};
}
-void RenderRasterSource::setCacheSize(size_t size) {
- tilePyramid.setCacheSize(size);
-}
-
void RenderRasterSource::onLowMemory() {
tilePyramid.onLowMemory();
}
diff --git a/src/mbgl/renderer/sources/render_raster_source.hpp b/src/mbgl/renderer/sources/render_raster_source.hpp
index 5690ba80ea..01de812309 100644
--- a/src/mbgl/renderer/sources/render_raster_source.hpp
+++ b/src/mbgl/renderer/sources/render_raster_source.hpp
@@ -8,48 +8,43 @@ namespace mbgl {
class RenderRasterSource : public RenderSource {
public:
- RenderRasterSource(const style::RasterSource::Impl&);
+ RenderRasterSource(Immutable<style::RasterSource::Impl>);
bool isLoaded() const final;
- // Called when the camera has changed. May load new tiles, unload obsolete tiles, or
- // trigger re-placement of existing complete tiles.
- void updateTiles(const TileParameters&) final;
+ void update(Immutable<style::Source::Impl>,
+ const std::vector<Immutable<style::Layer::Impl>>&,
+ bool needsRendering,
+ bool needsRelayout,
+ const TileParameters&) final;
- // Removes all tiles (by putting them into the cache).
- void removeTiles() final;
+ void startRender(PaintParameters&) final;
+ void finishRender(PaintParameters&) final;
- // Remove all tiles and clear the cache.
- void invalidateTiles() final;
-
- // Request that all loaded tiles re-run the layout operation on the existing source
- // data with fresh style information.
- void reloadTiles() final;
-
- void startRender(algorithm::ClipIDGenerator&,
- const mat4& projMatrix,
- const mat4& clipMatrix,
- const TransformState&) final;
- void finishRender(Painter&) final;
-
- std::map<UnwrappedTileID, RenderTile>& getRenderTiles() 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 final;
std::vector<Feature>
querySourceFeatures(const SourceQueryOptions&) const final;
- void setCacheSize(size_t) final;
void onLowMemory() final;
void dumpDebugLogs() const final;
private:
- const style::RasterSource::Impl& impl;
+ const style::RasterSource::Impl& impl() const;
+
TilePyramid tilePyramid;
optional<std::vector<std::string>> tileURLTemplates;
};
+template <>
+inline bool RenderSource::is<RenderRasterSource>() const {
+ return baseImpl->type == SourceType::Raster;
+}
+
} // namespace mbgl
diff --git a/src/mbgl/renderer/sources/render_vector_source.cpp b/src/mbgl/renderer/sources/render_vector_source.cpp
index 0db4698a81..ca3071c6b0 100644
--- a/src/mbgl/renderer/sources/render_vector_source.cpp
+++ b/src/mbgl/renderer/sources/render_vector_source.cpp
@@ -1,5 +1,6 @@
#include <mbgl/renderer/sources/render_vector_source.hpp>
#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/tile/vector_tile.hpp>
#include <mbgl/algorithm/generate_clip_ids.hpp>
@@ -9,35 +10,29 @@ namespace mbgl {
using namespace style;
-RenderVectorSource::RenderVectorSource(const style::VectorSource::Impl& impl_)
- : RenderSource(impl_),
- impl(impl_) {
+RenderVectorSource::RenderVectorSource(Immutable<style::VectorSource::Impl> impl_)
+ : RenderSource(impl_) {
tilePyramid.setObserver(this);
}
-bool RenderVectorSource::isLoaded() const {
- return tilePyramid.isLoaded();
+const style::VectorSource::Impl& RenderVectorSource::impl() const {
+ return static_cast<const style::VectorSource::Impl&>(*baseImpl);
}
-void RenderVectorSource::invalidateTiles() {
- tilePyramid.invalidateTiles();
+bool RenderVectorSource::isLoaded() const {
+ return tilePyramid.isLoaded();
}
-void RenderVectorSource::startRender(algorithm::ClipIDGenerator& generator, const mat4& projMatrix, const mat4& clipMatrix, const TransformState& transform) {
- generator.update(tilePyramid.getRenderTiles());
- tilePyramid.startRender(projMatrix, clipMatrix, transform);
-}
+void RenderVectorSource::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_);
-void RenderVectorSource::finishRender(Painter& painter) {
- tilePyramid.finishRender(painter);
-}
+ enabled = needsRendering;
-std::map<UnwrappedTileID, RenderTile>& RenderVectorSource::getRenderTiles() {
- return tilePyramid.getRenderTiles();
-}
-
-void RenderVectorSource::updateTiles(const TileParameters& parameters) {
- optional<Tileset> tileset = impl.getTileset();
+ optional<Tileset> tileset = impl().getTileset();
if (!tileset) {
return;
@@ -45,41 +40,51 @@ void RenderVectorSource::updateTiles(const TileParameters& parameters) {
if (tileURLTemplates != tileset->tiles) {
tileURLTemplates = tileset->tiles;
- tilePyramid.invalidateTiles();
+
+ // TODO: this removes existing buckets, and will cause flickering.
+ // Should instead refresh tile data in place.
+ tilePyramid.tiles.clear();
+ tilePyramid.renderTiles.clear();
+ tilePyramid.cache.clear();
}
- tilePyramid.updateTiles(parameters,
- SourceType::Vector,
- util::tileSize,
- tileset->zoomRange,
- [&] (const OverscaledTileID& tileID) {
- return std::make_unique<VectorTile>(tileID, impl.id, parameters, *tileset);
- });
+ tilePyramid.update(layers,
+ needsRendering,
+ needsRelayout,
+ parameters,
+ SourceType::Vector,
+ util::tileSize,
+ tileset->zoomRange,
+ [&] (const OverscaledTileID& tileID) {
+ return std::make_unique<VectorTile>(tileID, impl().id, parameters, *tileset);
+ });
}
-void RenderVectorSource::removeTiles() {
- tilePyramid.removeTiles();
+void RenderVectorSource::startRender(PaintParameters& parameters) {
+ parameters.clipIDGenerator.update(tilePyramid.getRenderTiles());
+ tilePyramid.startRender(parameters);
}
-void RenderVectorSource::reloadTiles() {
- tilePyramid.reloadTiles();
+void RenderVectorSource::finishRender(PaintParameters& parameters) {
+ tilePyramid.finishRender(parameters);
+}
+
+std::vector<std::reference_wrapper<RenderTile>> RenderVectorSource::getRenderTiles() {
+ return tilePyramid.getRenderTiles();
}
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, options);
+ return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options);
}
std::vector<Feature> RenderVectorSource::querySourceFeatures(const SourceQueryOptions& options) const {
return tilePyramid.querySourceFeatures(options);
}
-void RenderVectorSource::setCacheSize(size_t size) {
- tilePyramid.setCacheSize(size);
-}
-
void RenderVectorSource::onLowMemory() {
tilePyramid.onLowMemory();
}
diff --git a/src/mbgl/renderer/sources/render_vector_source.hpp b/src/mbgl/renderer/sources/render_vector_source.hpp
index 36d75e0982..5e5c6d1108 100644
--- a/src/mbgl/renderer/sources/render_vector_source.hpp
+++ b/src/mbgl/renderer/sources/render_vector_source.hpp
@@ -8,48 +8,43 @@ namespace mbgl {
class RenderVectorSource : public RenderSource {
public:
- RenderVectorSource(const style::VectorSource::Impl&);
+ RenderVectorSource(Immutable<style::VectorSource::Impl>);
bool isLoaded() const final;
- // Called when the camera has changed. May load new tiles, unload obsolete tiles, or
- // trigger re-placement of existing complete tiles.
- void updateTiles(const TileParameters&) final;
+ void update(Immutable<style::Source::Impl>,
+ const std::vector<Immutable<style::Layer::Impl>>&,
+ bool needsRendering,
+ bool needsRelayout,
+ const TileParameters&) final;
- // Removes all tiles (by putting them into the cache).
- void removeTiles() final;
+ void startRender(PaintParameters&) final;
+ void finishRender(PaintParameters&) final;
- // Remove all tiles and clear the cache.
- void invalidateTiles() final;
-
- // Request that all loaded tiles re-run the layout operation on the existing source
- // data with fresh style information.
- void reloadTiles() final;
-
- void startRender(algorithm::ClipIDGenerator&,
- const mat4& projMatrix,
- const mat4& clipMatrix,
- const TransformState&) final;
- void finishRender(Painter&) final;
-
- std::map<UnwrappedTileID, RenderTile>& getRenderTiles() 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 final;
std::vector<Feature>
querySourceFeatures(const SourceQueryOptions&) const final;
- void setCacheSize(size_t) final;
void onLowMemory() final;
void dumpDebugLogs() const final;
private:
- const style::VectorSource::Impl& impl;
+ const style::VectorSource::Impl& impl() const;
+
TilePyramid tilePyramid;
optional<std::vector<std::string>> tileURLTemplates;
};
+template <>
+inline bool RenderSource::is<RenderVectorSource>() const {
+ return baseImpl->type == SourceType::Vector;
+}
+
} // namespace mbgl
diff --git a/src/mbgl/renderer/style_diff.cpp b/src/mbgl/renderer/style_diff.cpp
new file mode 100644
index 0000000000..0017280310
--- /dev/null
+++ b/src/mbgl/renderer/style_diff.cpp
@@ -0,0 +1,79 @@
+#include <mbgl/renderer/style_diff.hpp>
+#include <mbgl/style/layer_impl.hpp>
+#include <mbgl/util/immutable.hpp>
+#include <mbgl/util/variant.hpp>
+#include <mbgl/util/longest_common_subsequence.hpp>
+
+namespace mbgl {
+
+template <class T, class Eq>
+StyleDifference<T> diff(const Immutable<std::vector<T>>& a,
+ const Immutable<std::vector<T>>& b,
+ const Eq& eq) {
+ StyleDifference<T> result;
+
+ if (a == b) {
+ return result;
+ }
+
+ std::vector<T> lcs;
+
+ longest_common_subsequence(a->begin(), a->end(), b->begin(), b->end(), std::back_inserter(lcs), eq);
+
+ auto aIt = a->begin();
+ auto bIt = b->begin();
+ auto lIt = lcs.begin();
+
+ while (aIt != a->end() || bIt != b->end()) {
+ if (aIt != a->end() && (lIt == lcs.end() || !eq(*lIt, *aIt))) {
+ result.removed.emplace((*aIt)->id, *aIt);
+ aIt++;
+ } else if (bIt != b->end() && (lIt == lcs.end() || !eq(*lIt, *bIt))) {
+ result.added.emplace((*bIt)->id, *bIt);
+ bIt++;
+ } else {
+ if (aIt->get() != bIt->get()) {
+ result.changed.emplace((*bIt)->id, StyleChange<T> { *aIt, *bIt });
+ }
+ aIt++;
+ bIt++;
+ lIt++;
+ }
+ }
+
+ return result;
+}
+
+ImageDifference diffImages(const Immutable<std::vector<ImmutableImage>>& a,
+ const Immutable<std::vector<ImmutableImage>>& b) {
+ return diff(a, b, [] (const ImmutableImage& lhs, const ImmutableImage& rhs) {
+ return lhs->id == rhs->id;
+ });
+}
+
+SourceDifference diffSources(const Immutable<std::vector<ImmutableSource>>& a,
+ const Immutable<std::vector<ImmutableSource>>& b) {
+ return diff(a, b, [] (const ImmutableSource& lhs, const ImmutableSource& rhs) {
+ return std::tie(lhs->id, lhs->type)
+ == std::tie(rhs->id, rhs->type);
+ });
+}
+
+LayerDifference diffLayers(const Immutable<std::vector<ImmutableLayer>>& a,
+ const Immutable<std::vector<ImmutableLayer>>& b) {
+ return diff(a, b, [] (const ImmutableLayer& lhs, const ImmutableLayer& rhs) {
+ return std::tie(lhs->id, lhs->type)
+ == std::tie(rhs->id, rhs->type);
+ });
+}
+
+bool hasLayoutDifference(const LayerDifference& layerDiff, const std::string& layerID) {
+ if (layerDiff.added.count(layerID))
+ return true;
+ const auto it = layerDiff.changed.find(layerID);
+ if (it == layerDiff.changed.end())
+ return false;
+ return it->second.before->hasLayoutDifference(*it->second.after);
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/style_diff.hpp b/src/mbgl/renderer/style_diff.hpp
new file mode 100644
index 0000000000..a5b42fc662
--- /dev/null
+++ b/src/mbgl/renderer/style_diff.hpp
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <mbgl/style/image_impl.hpp>
+#include <mbgl/style/source_impl.hpp>
+#include <mbgl/style/layer_impl.hpp>
+#include <mbgl/util/immutable.hpp>
+#include <mbgl/util/variant.hpp>
+
+#include <unordered_map>
+
+namespace mbgl {
+
+template <class T>
+class StyleChange {
+public:
+ T before;
+ T after;
+};
+
+template <class T>
+class StyleDifference {
+public:
+ std::unordered_map<std::string, T> added;
+ std::unordered_map<std::string, T> removed;
+ std::unordered_map<std::string, StyleChange<T>> changed;
+};
+
+using ImmutableImage = Immutable<style::Image::Impl>;
+using ImageDifference = StyleDifference<ImmutableImage>;
+
+ImageDifference diffImages(const Immutable<std::vector<ImmutableImage>>&,
+ const Immutable<std::vector<ImmutableImage>>&);
+
+using ImmutableSource = Immutable<style::Source::Impl>;
+using SourceDifference = StyleDifference<ImmutableSource>;
+
+SourceDifference diffSources(const Immutable<std::vector<ImmutableSource>>&,
+ const Immutable<std::vector<ImmutableSource>>&);
+
+using ImmutableLayer = Immutable<style::Layer::Impl>;
+using LayerDifference = StyleDifference<ImmutableLayer>;
+
+LayerDifference diffLayers(const Immutable<std::vector<ImmutableLayer>>&,
+ const Immutable<std::vector<ImmutableLayer>>&);
+
+bool hasLayoutDifference(const LayerDifference&, const std::string& layerID);
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/tile_mask.hpp b/src/mbgl/renderer/tile_mask.hpp
new file mode 100644
index 0000000000..5f24d63ba4
--- /dev/null
+++ b/src/mbgl/renderer/tile_mask.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <mbgl/tile/tile_id.hpp>
+
+#include <set>
+
+namespace mbgl {
+
+// A TileMask is a set of TileIDs that describe what part of a tile should be rendered. It omits
+// those parts of the tile that are covered by other/better tiles. If the entire tile should be
+// rendered, it contains the { 0, 0, 0 } tile. If it's empty, no part of the tile will be rendered.
+// TileMasks are typically generated with algorithm::updateTileMasks().
+using TileMask = std::set<CanonicalTileID>;
+
+} // namespace mbgl
diff --git a/src/mbgl/renderer/tile_parameters.hpp b/src/mbgl/renderer/tile_parameters.hpp
index 8f04baaec5..665c7490d2 100644
--- a/src/mbgl/renderer/tile_parameters.hpp
+++ b/src/mbgl/renderer/tile_parameters.hpp
@@ -8,40 +8,21 @@ class TransformState;
class Scheduler;
class FileSource;
class AnnotationManager;
-
-namespace style {
-class Style;
-} // namespace style
+class ImageManager;
+class GlyphManager;
class TileParameters {
public:
- TileParameters(float pixelRatio_,
- MapDebugOptions debugOptions_,
- const TransformState& transformState_,
- Scheduler& workerScheduler_,
- FileSource& fileSource_,
- const MapMode mode_,
- AnnotationManager& annotationManager_,
- style::Style& style_)
- : pixelRatio(pixelRatio_),
- debugOptions(debugOptions_),
- transformState(transformState_),
- workerScheduler(workerScheduler_),
- fileSource(fileSource_),
- mode(mode_),
- annotationManager(annotationManager_),
- style(style_) {}
-
- float pixelRatio;
- MapDebugOptions debugOptions;
+ const float pixelRatio;
+ const MapDebugOptions debugOptions;
const TransformState& transformState;
Scheduler& workerScheduler;
FileSource& fileSource;
const MapMode mode;
AnnotationManager& annotationManager;
-
- // TODO: remove
- style::Style& style;
+ ImageManager& imageManager;
+ GlyphManager& glyphManager;
+ const uint8_t prefetchZoomDelta;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp
index 144afcb4f6..6cd9bd9ebd 100644
--- a/src/mbgl/renderer/tile_pyramid.cpp
+++ b/src/mbgl/renderer/tile_pyramid.cpp
@@ -1,10 +1,10 @@
#include <mbgl/renderer/tile_pyramid.hpp>
#include <mbgl/renderer/render_tile.hpp>
-#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/render_source.hpp>
#include <mbgl/renderer/tile_parameters.hpp>
+#include <mbgl/renderer/query.hpp>
#include <mbgl/map/transform.hpp>
-#include <mbgl/map/query.hpp>
#include <mbgl/text/placement_config.hpp>
#include <mbgl/math/clamp.hpp>
#include <mbgl/util/tile_cover.hpp>
@@ -39,50 +39,77 @@ bool TilePyramid::isLoaded() const {
return true;
}
-void TilePyramid::invalidateTiles() {
- tiles.clear();
- renderTiles.clear();
- cache.clear();
-}
-
-void TilePyramid::startRender(const mat4& projMatrix,
- const mat4& clipMatrix,
- const TransformState& transform) {
- for (auto& pair : renderTiles) {
- auto& tile = pair.second;
- tile.calculateMatrices(projMatrix, clipMatrix, transform);
+void TilePyramid::startRender(PaintParameters& parameters) {
+ for (auto& tile : renderTiles) {
+ tile.startRender(parameters);
}
}
-void TilePyramid::finishRender(Painter& painter) {
- for (auto& pair : renderTiles) {
- auto& tile = pair.second;
- if (tile.used) {
- painter.renderTileDebug(tile);
- }
+void TilePyramid::finishRender(PaintParameters& parameters) {
+ for (auto& tile : renderTiles) {
+ tile.finishRender(parameters);
}
}
-std::map<UnwrappedTileID, RenderTile>& TilePyramid::getRenderTiles() {
- return renderTiles;
+std::vector<std::reference_wrapper<RenderTile>> TilePyramid::getRenderTiles() {
+ return { renderTiles.begin(), renderTiles.end() };
}
-void TilePyramid::updateTiles(const TileParameters& parameters,
- const SourceType type,
- const uint16_t tileSize,
- const Range<uint8_t> zoomRange,
- std::function<std::unique_ptr<Tile> (const OverscaledTileID&)> createTile) {
+void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layers,
+ const bool needsRendering,
+ const bool needsRelayout,
+ const TileParameters& parameters,
+ const SourceType type,
+ const uint16_t tileSize,
+ const Range<uint8_t> zoomRange,
+ std::function<std::unique_ptr<Tile> (const OverscaledTileID&)> createTile) {
+ // If we need a relayout, abandon any cached tiles; they're now stale.
+ if (needsRelayout) {
+ cache.clear();
+ }
+
+ // If we're not going to render anything, move our existing tiles into
+ // the cache (if they're not stale) or abandon them, and return.
+ if (!needsRendering) {
+ if (!needsRelayout) {
+ for (auto& entry : tiles) {
+ cache.add(entry.first, std::move(entry.second));
+ }
+ }
+
+ tiles.clear();
+ renderTiles.clear();
+
+ return;
+ }
+
// Determine the overzooming/underzooming amounts and required tiles.
int32_t overscaledZoom = util::coveringZoomLevel(parameters.transformState.getZoom(), type, tileSize);
int32_t tileZoom = overscaledZoom;
+ int32_t panZoom = zoomRange.max;
std::vector<UnwrappedTileID> idealTiles;
+ std::vector<UnwrappedTileID> panTiles;
+
if (overscaledZoom >= zoomRange.min) {
int32_t idealZoom = std::min<int32_t>(zoomRange.max, overscaledZoom);
// Make sure we're not reparsing overzoomed raster tiles.
if (type == SourceType::Raster) {
tileZoom = idealZoom;
+
+ // FIXME: Prefetching is only enabled for raster
+ // tiles until we fix #7026.
+
+ // Request lower zoom level tiles (if configure to do so) in an attempt
+ // to show something on the screen faster at the cost of a little of bandwidth.
+ if (parameters.prefetchZoomDelta) {
+ panZoom = std::max<int32_t>(tileZoom - parameters.prefetchZoomDelta, zoomRange.min);
+ }
+
+ if (panZoom < tileZoom) {
+ panTiles = util::tileCover(parameters.transformState, panZoom);
+ }
}
idealTiles = util::tileCover(parameters.transformState, idealZoom);
@@ -95,8 +122,13 @@ void TilePyramid::updateTiles(const TileParameters& parameters,
std::set<OverscaledTileID> retain;
auto retainTileFn = [&](Tile& tile, Resource::Necessity necessity) -> void {
- retain.emplace(tile.id);
- tile.setNecessity(necessity);
+ if (retain.emplace(tile.id).second) {
+ tile.setNecessity(necessity);
+ }
+
+ if (needsRelayout) {
+ tile.setLayers(layers);
+ }
};
auto getTileFn = [&](const OverscaledTileID& tileID) -> Tile* {
auto it = tiles.find(tileID);
@@ -108,6 +140,7 @@ void TilePyramid::updateTiles(const TileParameters& parameters,
tile = createTile(tileID);
if (tile) {
tile->setObserver(observer);
+ tile->setLayers(layers);
}
}
if (!tile) {
@@ -116,10 +149,16 @@ void TilePyramid::updateTiles(const TileParameters& parameters,
return tiles.emplace(tileID, std::move(tile)).first->second.get();
};
auto renderTileFn = [&](const UnwrappedTileID& tileID, Tile& tile) {
- renderTiles.emplace(tileID, RenderTile{ tileID, tile });
+ renderTiles.emplace_back(tileID, tile);
};
renderTiles.clear();
+
+ if (!panTiles.empty()) {
+ algorithm::updateRenderables(getTileFn, createTileFn, retainTileFn,
+ [](const UnwrappedTileID&, Tile&) {}, panTiles, zoomRange, panZoom);
+ }
+
algorithm::updateRenderables(getTileFn, createTileFn, retainTileFn, renderTileFn,
idealTiles, zoomRange, tileZoom);
@@ -132,54 +171,41 @@ void TilePyramid::updateTiles(const TileParameters& parameters,
cache.setSize(conservativeCacheSize);
}
- removeStaleTiles(retain);
-
- const PlacementConfig config { parameters.transformState.getAngle(),
- parameters.transformState.getPitch(),
- parameters.debugOptions & MapDebugOptions::Collision };
-
- for (auto& pair : tiles) {
- pair.second->setPlacementConfig(config);
- }
-}
-
-// Moves all tiles to the cache except for those specified in the retain set.
-void TilePyramid::removeStaleTiles(const std::set<OverscaledTileID>& retain) {
// Remove stale tiles. This goes through the (sorted!) tiles map and retain set in lockstep
// and removes items from tiles that don't have the corresponding key in the retain set.
- auto tilesIt = tiles.begin();
- auto retainIt = retain.begin();
- while (tilesIt != tiles.end()) {
- if (retainIt == retain.end() || tilesIt->first < *retainIt) {
- tilesIt->second->setNecessity(Tile::Necessity::Optional);
- cache.add(tilesIt->first, std::move(tilesIt->second));
- tiles.erase(tilesIt++);
- } else {
- if (!(*retainIt < tilesIt->first)) {
- ++tilesIt;
+ {
+ auto tilesIt = tiles.begin();
+ auto retainIt = retain.begin();
+ while (tilesIt != tiles.end()) {
+ if (retainIt == retain.end() || tilesIt->first < *retainIt) {
+ if (!needsRelayout) {
+ tilesIt->second->setNecessity(Tile::Necessity::Optional);
+ cache.add(tilesIt->first, std::move(tilesIt->second));
+ }
+ tiles.erase(tilesIt++);
+ } else {
+ if (!(*retainIt < tilesIt->first)) {
+ ++tilesIt;
+ }
+ ++retainIt;
}
- ++retainIt;
}
}
-}
-
-void TilePyramid::removeTiles() {
- renderTiles.clear();
- if (!tiles.empty()) {
- removeStaleTiles({});
- }
-}
-
-void TilePyramid::reloadTiles() {
- cache.clear();
for (auto& pair : tiles) {
- pair.second->redoLayout();
+ 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);
}
}
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 {
std::unordered_map<std::string, std::vector<Feature>> result;
if (renderTiles.empty() || geometry.empty()) {
@@ -195,18 +221,14 @@ std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRendered
mapbox::geometry::box<double> box = mapbox::geometry::envelope(queryGeometry);
-
- auto sortRenderTiles = [](const RenderTile& a, const RenderTile& b) {
+ std::vector<std::reference_wrapper<const RenderTile>> sortedTiles{ renderTiles.begin(),
+ renderTiles.end() };
+ std::sort(sortedTiles.begin(), sortedTiles.end(), [](const RenderTile& a, const RenderTile& b) {
return std::tie(a.id.canonical.z, a.id.canonical.y, a.id.wrap, a.id.canonical.x) <
std::tie(b.id.canonical.z, b.id.canonical.y, b.id.wrap, b.id.canonical.x);
- };
- std::vector<std::reference_wrapper<const RenderTile>> sortedTiles;
- std::transform(renderTiles.cbegin(), renderTiles.cend(), std::back_inserter(sortedTiles),
- [](const auto& pair) { return std::ref(pair.second); });
- std::sort(sortedTiles.begin(), sortedTiles.end(), sortRenderTiles);
+ });
- for (const auto& renderTileRef : sortedTiles) {
- const RenderTile& renderTile = renderTileRef.get();
+ for (const RenderTile& renderTile : sortedTiles) {
GeometryCoordinate tileSpaceBoundsMin = TileCoordinate::toGeometryCoordinate(renderTile.id, box.min);
if (tileSpaceBoundsMin.x >= util::EXTENT || tileSpaceBoundsMin.y >= util::EXTENT) {
continue;
@@ -226,6 +248,7 @@ std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRendered
renderTile.tile.queryRenderedFeatures(result,
tileSpaceQueryGeometry,
transformState,
+ layers,
options);
}
diff --git a/src/mbgl/renderer/tile_pyramid.hpp b/src/mbgl/renderer/tile_pyramid.hpp
index b51c5342de..73a8d34c1c 100644
--- a/src/mbgl/renderer/tile_pyramid.hpp
+++ b/src/mbgl/renderer/tile_pyramid.hpp
@@ -5,6 +5,7 @@
#include <mbgl/tile/tile.hpp>
#include <mbgl/tile/tile_cache.hpp>
#include <mbgl/style/types.hpp>
+#include <mbgl/style/layer_impl.hpp>
#include <mbgl/util/mat4.hpp>
#include <mbgl/util/feature.hpp>
@@ -17,9 +18,10 @@
namespace mbgl {
-class Painter;
+class PaintParameters;
class TransformState;
class RenderTile;
+class RenderLayer;
class RenderedQueryOptions;
class SourceQueryOptions;
class TileParameters;
@@ -31,34 +33,24 @@ public:
bool isLoaded() const;
- // Called when the camera has changed. May load new tiles, unload obsolete tiles, or
- // trigger re-placement of existing complete tiles.
- void updateTiles(const TileParameters&,
- SourceType type,
- uint16_t tileSize,
- Range<uint8_t> zoomRange,
- std::function<std::unique_ptr<Tile> (const OverscaledTileID&)> createTile);
+ void update(const std::vector<Immutable<style::Layer::Impl>>&,
+ bool needsRendering,
+ bool needsRelayout,
+ const TileParameters&,
+ SourceType type,
+ uint16_t tileSize,
+ Range<uint8_t> zoomRange,
+ std::function<std::unique_ptr<Tile> (const OverscaledTileID&)> createTile);
- // Removes all tiles (by putting them into the cache).
- void removeTiles();
+ void startRender(PaintParameters&);
+ void finishRender(PaintParameters&);
- // Remove all tiles and clear the cache.
- void invalidateTiles();
-
- // Request that all loaded tiles re-run the layout operation on the existing source
- // data with fresh style information.
- void reloadTiles();
-
- void startRender(const mat4& projMatrix,
- const mat4& clipMatrix,
- const TransformState&);
- void finishRender(Painter&);
-
- std::map<UnwrappedTileID, RenderTile>& getRenderTiles();
+ std::vector<std::reference_wrapper<RenderTile>> getRenderTiles();
std::unordered_map<std::string, std::vector<Feature>>
queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
+ const std::vector<const RenderLayer*>&,
const RenderedQueryOptions& options) const;
std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const;
@@ -71,12 +63,10 @@ public:
bool enabled = false;
- void removeStaleTiles(const std::set<OverscaledTileID>&);
-
std::map<OverscaledTileID, std::unique_ptr<Tile>> tiles;
TileCache cache;
- std::map<UnwrappedTileID, RenderTile> renderTiles;
+ std::vector<RenderTile> renderTiles;
TileObserver* observer = nullptr;
};
diff --git a/src/mbgl/renderer/cascade_parameters.hpp b/src/mbgl/renderer/transition_parameters.hpp
index 4096cc5a6b..c47aa2e35f 100644
--- a/src/mbgl/renderer/cascade_parameters.hpp
+++ b/src/mbgl/renderer/transition_parameters.hpp
@@ -1,16 +1,14 @@
#pragma once
#include <mbgl/util/chrono.hpp>
-#include <mbgl/style/class_dictionary.hpp>
#include <mbgl/style/transition_options.hpp>
#include <vector>
namespace mbgl {
-class CascadeParameters {
+class TransitionParameters {
public:
- std::vector<style::ClassID> classes;
TimePoint now;
style::TransitionOptions transition;
};
diff --git a/src/mbgl/renderer/transitioning_property.hpp b/src/mbgl/renderer/transitioning_property.hpp
deleted file mode 100644
index c211ccf116..0000000000
--- a/src/mbgl/renderer/transitioning_property.hpp
+++ /dev/null
@@ -1,75 +0,0 @@
-#pragma once
-
-#include <mbgl/style/property_value.hpp>
-#include <mbgl/style/data_driven_property_value.hpp>
-#include <mbgl/style/transition_options.hpp>
-#include <mbgl/util/interpolate.hpp>
-
-#include <utility>
-
-namespace mbgl {
-
-template <class Value>
-class TransitioningProperty {
-public:
- TransitioningProperty() = default;
-
- TransitioningProperty(Value value_,
- TransitioningProperty<Value> prior_,
- style::TransitionOptions transition,
- TimePoint now)
- : begin(now + transition.delay.value_or(Duration::zero())),
- end(begin + transition.duration.value_or(Duration::zero())),
- value(std::move(value_)) {
- if (transition.isDefined()) {
- prior = { std::move(prior_) };
- }
- }
-
- template <class Evaluator>
- auto evaluate(const Evaluator& evaluator, TimePoint now) {
- auto finalValue = value.evaluate(evaluator);
- if (!prior) {
- // No prior value.
- return finalValue;
- } else if (now >= end) {
- // Transition from prior value is now complete.
- prior = {};
- return finalValue;
- } else if (value.isDataDriven()) {
- // Transitions to data-driven properties are not supported.
- // We snap immediately to the data-driven value so that, when we perform layout,
- // we see the data-driven function and can use it to populate vertex buffers.
- prior = {};
- return finalValue;
- } else if (now < begin) {
- // Transition hasn't started yet.
- return prior->get().evaluate(evaluator, now);
- } else {
- // Interpolate between recursively-calculated prior value and final.
- float t = std::chrono::duration<float>(now - begin) / (end - begin);
- return util::interpolate(prior->get().evaluate(evaluator, now), finalValue,
- util::DEFAULT_TRANSITION_EASE.solve(t, 0.001));
- }
- }
-
- bool hasTransition() const {
- return bool(prior);
- }
-
- bool isUndefined() const {
- return value.isUndefined();
- }
-
- const Value& getValue() const {
- return value;
- }
-
-private:
- optional<mapbox::util::recursive_wrapper<TransitioningProperty<Value>>> prior;
- TimePoint begin;
- TimePoint end;
- Value value;
-};
-
-} // namespace mbgl
diff --git a/src/mbgl/renderer/update_parameters.hpp b/src/mbgl/renderer/update_parameters.hpp
index ae54ac09e7..b54abc050d 100644
--- a/src/mbgl/renderer/update_parameters.hpp
+++ b/src/mbgl/renderer/update_parameters.hpp
@@ -1,26 +1,43 @@
#pragma once
#include <mbgl/map/mode.hpp>
-#include <mbgl/map/update.hpp>
+#include <mbgl/map/transform_state.hpp>
+#include <mbgl/style/light.hpp>
+#include <mbgl/style/image.hpp>
+#include <mbgl/style/source.hpp>
+#include <mbgl/style/layer.hpp>
+#include <mbgl/util/chrono.hpp>
+#include <mbgl/util/immutable.hpp>
+
+#include <vector>
namespace mbgl {
-class TransformState;
-class Scheduler;
-class FileSource;
class AnnotationManager;
class UpdateParameters {
public:
+ const bool styleLoaded;
const MapMode mode;
- const Update updateFlags;
const float pixelRatio;
const MapDebugOptions debugOptions;
const TimePoint timePoint;
- const TransformState& transformState;
- Scheduler& scheduler;
- FileSource& fileSource;
+ const TransformState transformState;
+
+ const std::string glyphURL;
+ const bool spriteLoaded;
+ const style::TransitionOptions transitionOptions;
+ const Immutable<style::Light::Impl> light;
+ const Immutable<std::vector<Immutable<style::Image::Impl>>> images;
+ const Immutable<std::vector<Immutable<style::Source::Impl>>> sources;
+ const Immutable<std::vector<Immutable<style::Layer::Impl>>> layers;
+
AnnotationManager& annotationManager;
+
+ const uint8_t prefetchZoomDelta;
+
+ // For still image requests, render requested
+ const bool stillImageRequest;
};
} // namespace mbgl