diff options
Diffstat (limited to 'src/mbgl/renderer')
84 files changed, 2265 insertions, 940 deletions
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..8b5743d500 100644 --- a/src/mbgl/renderer/circle_bucket.cpp +++ b/src/mbgl/renderer/buckets/circle_bucket.cpp @@ -1,9 +1,9 @@ -#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> diff --git a/src/mbgl/renderer/circle_bucket.hpp b/src/mbgl/renderer/buckets/circle_bucket.hpp index b048fd7675..b048fd7675 100644 --- a/src/mbgl/renderer/circle_bucket.hpp +++ b/src/mbgl/renderer/buckets/circle_bucket.hpp diff --git a/src/mbgl/renderer/debug_bucket.cpp b/src/mbgl/renderer/buckets/debug_bucket.cpp index 2a514989cf..acfe15d2fb 100644 --- a/src/mbgl/renderer/debug_bucket.cpp +++ b/src/mbgl/renderer/buckets/debug_bucket.cpp @@ -1,4 +1,4 @@ -#include <mbgl/renderer/debug_bucket.hpp> +#include <mbgl/renderer/buckets/debug_bucket.hpp> #include <mbgl/renderer/painter.hpp> #include <mbgl/programs/fill_program.hpp> #include <mbgl/geometry/debug_font_data.hpp> diff --git a/src/mbgl/renderer/debug_bucket.hpp b/src/mbgl/renderer/buckets/debug_bucket.hpp index 756e58a6de..756e58a6de 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..042d7b7506 100644 --- a/src/mbgl/renderer/fill_bucket.cpp +++ b/src/mbgl/renderer/buckets/fill_bucket.cpp @@ -1,9 +1,9 @@ -#include <mbgl/renderer/fill_bucket.hpp> +#include <mbgl/renderer/buckets/fill_bucket.hpp> #include <mbgl/renderer/painter.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> diff --git a/src/mbgl/renderer/fill_bucket.hpp b/src/mbgl/renderer/buckets/fill_bucket.hpp index 421d8b332b..421d8b332b 100644 --- a/src/mbgl/renderer/fill_bucket.hpp +++ b/src/mbgl/renderer/buckets/fill_bucket.hpp diff --git a/src/mbgl/renderer/fill_extrusion_bucket.cpp b/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp index 2b352ab66a..f61f1d1549 100644 --- a/src/mbgl/renderer/fill_extrusion_bucket.cpp +++ b/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp @@ -1,9 +1,9 @@ -#include <mbgl/renderer/fill_extrusion_bucket.hpp> +#include <mbgl/renderer/buckets/fill_extrusion_bucket.hpp> #include <mbgl/renderer/painter.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> diff --git a/src/mbgl/renderer/fill_extrusion_bucket.hpp b/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp index c54805d743..c54805d743 100644 --- a/src/mbgl/renderer/fill_extrusion_bucket.hpp +++ b/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp diff --git a/src/mbgl/renderer/line_bucket.cpp b/src/mbgl/renderer/buckets/line_bucket.cpp index 7bb4e2f202..3af3cd63d3 100644 --- a/src/mbgl/renderer/line_bucket.cpp +++ b/src/mbgl/renderer/buckets/line_bucket.cpp @@ -1,6 +1,6 @@ -#include <mbgl/renderer/line_bucket.hpp> +#include <mbgl/renderer/buckets/line_bucket.hpp> #include <mbgl/renderer/painter.hpp> -#include <mbgl/renderer/render_line_layer.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,7 +14,7 @@ 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()) { for (const auto& layer : layers) { @@ -183,7 +183,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); @@ -356,7 +356,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); @@ -480,7 +480,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 c319548714..34d8935953 100644 --- a/src/mbgl/renderer/line_bucket.hpp +++ b/src/mbgl/renderer/buckets/line_bucket.hpp @@ -19,7 +19,7 @@ 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; diff --git a/src/mbgl/renderer/buckets/raster_bucket.cpp b/src/mbgl/renderer/buckets/raster_bucket.cpp new file mode 100644 index 0000000000..49ec0065c3 --- /dev/null +++ b/src/mbgl/renderer/buckets/raster_bucket.cpp @@ -0,0 +1,53 @@ +#include <mbgl/renderer/buckets/raster_bucket.hpp> +#include <mbgl/renderer/layers/render_raster_layer.hpp> +#include <mbgl/programs/raster_program.hpp> +#include <mbgl/renderer/painter.hpp> +#include <mbgl/gl/context.hpp> +#include <mbgl/renderer/render_tile.hpp> + +namespace mbgl { + +using namespace style; + +RasterBucket::RasterBucket(UnassociatedImage&& image_) : image(std::move(image_)) { +} + +void RasterBucket::upload(gl::Context& context) { + if (!texture) { + texture = context.createTexture(image); + } + if (!vertices.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::render(Painter& painter, + PaintParameters& parameters, + const RenderLayer& layer, + const RenderTile& tile) { + painter.renderRaster(parameters, *this, *layer.as<RenderRasterLayer>(), tile.matrix, false); +} + +void RasterBucket::render(Painter& painter, + PaintParameters& parameters, + const RenderLayer& layer, + const mat4& matrix) { + painter.renderRaster(parameters, *this, *layer.as<RenderRasterLayer>(), matrix, true); +} + +bool RasterBucket::hasData() const { + return true; +} + +} // 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..b5cf7997d5 --- /dev/null +++ b/src/mbgl/renderer/buckets/raster_bucket.hpp @@ -0,0 +1,40 @@ +#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/util/image.hpp> +#include <mbgl/util/mat4.hpp> +#include <mbgl/util/optional.hpp> + +namespace mbgl { + +class RasterBucket : public Bucket { +public: + RasterBucket(UnassociatedImage&&); + + void upload(gl::Context&) override; + void render(Painter&, PaintParameters&, const RenderLayer&, const RenderTile&) override; + void render(Painter& painter, + PaintParameters& parameters, + const RenderLayer& layer, + const mat4& matrix); + bool hasData() const override; + + void clear(); + UnassociatedImage image; + optional<gl::Texture> texture; + + // 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; + gl::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..cbddade899 100644 --- a/src/mbgl/renderer/symbol_bucket.cpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp @@ -1,8 +1,9 @@ -#include <mbgl/renderer/symbol_bucket.hpp> +#include <mbgl/renderer/buckets/symbol_bucket.hpp> #include <mbgl/renderer/painter.hpp> -#include <mbgl/renderer/render_symbol_layer.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 +11,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, diff --git a/src/mbgl/renderer/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp index f7e4bcfa20..002b6e28b3 100644 --- a/src/mbgl/renderer/symbol_bucket.hpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp @@ -18,7 +18,7 @@ namespace mbgl { 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, @@ -57,6 +57,7 @@ public: gl::VertexVector<SymbolLayoutVertex> vertices; gl::IndexVector<gl::Triangles> triangles; gl::SegmentVector<SymbolIconAttributes> segments; + PremultipliedImage atlasImage; optional<gl::VertexBuffer<SymbolLayoutVertex>> vertexBuffer; optional<gl::IndexBuffer<gl::Triangles>> indexBuffer; @@ -70,8 +71,6 @@ public: optional<gl::VertexBuffer<CollisionBoxVertex>> vertexBuffer; optional<gl::IndexBuffer<gl::Lines>> indexBuffer; } collisionBox; - - SpriteAtlas* spriteAtlas = nullptr; }; } // namespace mbgl 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..869222b4eb 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) { 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..d0a106ede6 --- /dev/null +++ b/src/mbgl/renderer/image_manager.cpp @@ -0,0 +1,166 @@ +#include <mbgl/renderer/image_manager.hpp> +#include <mbgl/util/logging.hpp> +#include <mbgl/gl/context.hpp> + +namespace mbgl { + +void ImageManager::onSpriteLoaded() { + loaded = true; + for (const auto& entry : requestors) { + notify(*entry.first, entry.second); + } + requestors.clear(); +} + +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()) { + 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, ImageDependencies dependencies) { + // 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 : dependencies) { + if (images.find(dependency) == images.end()) { + hasAllDependencies = false; + } + } + } + if (isLoaded() || hasAllDependencies) { + notify(requestor, dependencies); + } else { + requestors.emplace(&requestor, std::move(dependencies)); + } +} + +void ImageManager::removeRequestor(ImageRequestor& requestor) { + requestors.erase(&requestor); +} + +void ImageManager::notify(ImageRequestor& requestor, const ImageDependencies& dependencies) const { + ImageMap response; + + for (const auto& dependency : dependencies) { + auto it = images.find(dependency); + if (it != images.end()) { + response.emplace(*it); + } + } + + requestor.onImagesAvailable(response); +} + +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..9a9a4ce997 --- /dev/null +++ b/src/mbgl/renderer/image_manager.hpp @@ -0,0 +1,94 @@ +#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) = 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 onSpriteLoaded(); + + bool isLoaded() const { + return loaded; + } + + 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&, ImageDependencies); + void removeRequestor(ImageRequestor&); + +private: + void notify(ImageRequestor&, const ImageDependencies&) const; + + bool loaded = false; + + std::unordered_map<ImageRequestor*, ImageDependencies> 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/render_background_layer.cpp b/src/mbgl/renderer/layers/render_background_layer.cpp index 485d4b16c6..702977cd23 100644 --- a/src/mbgl/renderer/render_background_layer.cpp +++ b/src/mbgl/renderer/layers/render_background_layer.cpp @@ -1,16 +1,16 @@ -#include <mbgl/renderer/render_background_layer.hpp> +#include <mbgl/renderer/layers/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) { +RenderBackgroundLayer::RenderBackgroundLayer(Immutable<style::BackgroundLayer::Impl> _impl) + : RenderLayer(style::LayerType::Background, _impl), + unevaluated(impl().paint.untransitioned()) { } -std::unique_ptr<RenderLayer> RenderBackgroundLayer::clone() const { - return std::make_unique<RenderBackgroundLayer>(*this); +const style::BackgroundLayer::Impl& RenderBackgroundLayer::impl() const { + return static_cast<const style::BackgroundLayer::Impl&>(*baseImpl); } std::unique_ptr<Bucket> RenderBackgroundLayer::createBucket(const BucketParameters &, @@ -19,8 +19,8 @@ std::unique_ptr<Bucket> RenderBackgroundLayer::createBucket(const BucketParamete return nullptr; } -void RenderBackgroundLayer::cascade(const CascadeParameters ¶meters) { - unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated)); +void RenderBackgroundLayer::transition(const TransitionParameters ¶meters) { + unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated)); } void RenderBackgroundLayer::evaluate(const PropertyEvaluationParameters ¶meters) { @@ -34,4 +34,4 @@ bool RenderBackgroundLayer::hasTransition() const { return unevaluated.hasTransition(); } -} +} // namespace mbgl diff --git a/src/mbgl/renderer/render_background_layer.hpp b/src/mbgl/renderer/layers/render_background_layer.hpp index b1f709953f..0fba3d2bb1 100644 --- a/src/mbgl/renderer/render_background_layer.hpp +++ b/src/mbgl/renderer/layers/render_background_layer.hpp @@ -1,20 +1,17 @@ #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; @@ -22,9 +19,9 @@ public: // 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 +29,4 @@ inline bool RenderLayer::is<RenderBackgroundLayer>() const { return type == style::LayerType::Background; } -} +} // namespace mbgl diff --git a/src/mbgl/renderer/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp index f59c174dd3..51a5ecd7d6 100644 --- a/src/mbgl/renderer/render_circle_layer.cpp +++ b/src/mbgl/renderer/layers/render_circle_layer.cpp @@ -1,5 +1,5 @@ -#include <mbgl/renderer/render_circle_layer.hpp> -#include <mbgl/renderer/circle_bucket.hpp> +#include <mbgl/renderer/layers/render_circle_layer.hpp> +#include <mbgl/renderer/buckets/circle_bucket.hpp> #include <mbgl/style/layers/circle_layer_impl.hpp> #include <mbgl/geometry/feature_index.hpp> #include <mbgl/util/math.hpp> @@ -7,21 +7,21 @@ namespace mbgl { -RenderCircleLayer::RenderCircleLayer(const style::CircleLayer::Impl& _impl) - : RenderLayer(style::LayerType::Circle, _impl), - impl(&_impl) { +RenderCircleLayer::RenderCircleLayer(Immutable<style::CircleLayer::Impl> _impl) + : RenderLayer(style::LayerType::Circle, _impl), + unevaluated(impl().paint.untransitioned()) { } -std::unique_ptr<RenderLayer> RenderCircleLayer::clone() const { - return std::make_unique<RenderCircleLayer>(*this); +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::cascade(const CascadeParameters& parameters) { - unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated)); +void RenderCircleLayer::transition(const TransitionParameters& parameters) { + unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated)); } void RenderCircleLayer::evaluate(const PropertyEvaluationParameters& parameters) { @@ -64,4 +64,4 @@ bool RenderCircleLayer::queryIntersectsFeature( 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..4ae7399ad1 100644 --- a/src/mbgl/renderer/render_circle_layer.hpp +++ b/src/mbgl/renderer/layers/render_circle_layer.hpp @@ -1,20 +1,17 @@ #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; @@ -29,9 +26,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 +36,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..4d6084075d --- /dev/null +++ b/src/mbgl/renderer/layers/render_custom_layer.cpp @@ -0,0 +1,76 @@ +#include <mbgl/renderer/layers/render_custom_layer.hpp> +#include <mbgl/renderer/painter.hpp> +#include <mbgl/renderer/paint_parameters.hpp> +#include <mbgl/style/layers/custom_layer_impl.hpp> +#include <mbgl/map/transform_state.hpp> +#include <mbgl/map/backend_scope.hpp> + +namespace mbgl { + +using namespace style; + +RenderCustomLayer::RenderCustomLayer(Immutable<style::CustomLayer::Impl> _impl) + : RenderLayer(LayerType::Custom, _impl) { +} + +RenderCustomLayer::~RenderCustomLayer() { + assert(BackendScope::exists()); + if (initialized && 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(Painter& painter, PaintParameters& paintParameters, RenderSource*) { + if (!initialized) { + assert(impl().initializeFn); + impl().initializeFn(impl().context); + initialized = true; + } + + gl::Context& context = painter.context; + const TransformState& state = painter.state; + + // Reset GL state to a known state so the CustomLayer always has a clean slate. + context.vertexArrayObject = 0; + context.setDepthMode(painter.depthModeForSublayer(0, gl::DepthMode::ReadOnly)); + context.setStencilMode(gl::StencilMode::disabled()); + context.setColorMode(painter.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.view.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..dd52d315cf 100644 --- a/src/mbgl/renderer/render_custom_layer.hpp +++ b/src/mbgl/renderer/layers/render_custom_layer.hpp @@ -1,25 +1,26 @@ #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(Painter&, PaintParameters&, RenderSource*) final; - const style::CustomLayer::Impl* const impl; + const style::CustomLayer::Impl& impl() const; + +private: + bool initialized = false; }; template <> @@ -27,4 +28,4 @@ inline bool RenderLayer::is<RenderCustomLayer>() const { return type == style::LayerType::Custom; } -} +} // namespace mbgl diff --git a/src/mbgl/renderer/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp index f6ba164d8c..cd69316670 100644 --- a/src/mbgl/renderer/render_fill_extrusion_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp @@ -1,5 +1,5 @@ -#include <mbgl/renderer/render_fill_extrusion_layer.hpp> -#include <mbgl/renderer/fill_extrusion_bucket.hpp> +#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp> +#include <mbgl/renderer/buckets/fill_extrusion_bucket.hpp> #include <mbgl/style/layers/fill_extrusion_layer_impl.hpp> #include <mbgl/geometry/feature_index.hpp> #include <mbgl/util/math.hpp> @@ -7,21 +7,21 @@ namespace mbgl { -RenderFillExtrusionLayer::RenderFillExtrusionLayer(const style::FillExtrusionLayer::Impl& _impl) - : RenderLayer(style::LayerType::FillExtrusion, _impl), - impl(&_impl) { +RenderFillExtrusionLayer::RenderFillExtrusionLayer(Immutable<style::FillExtrusionLayer::Impl> _impl) + : RenderLayer(style::LayerType::FillExtrusion, _impl), + unevaluated(impl().paint.untransitioned()) { } -std::unique_ptr<RenderLayer> RenderFillExtrusionLayer::clone() const { - return std::make_unique<RenderFillExtrusionLayer>(*this); +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::cascade(const CascadeParameters& parameters) { - unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated)); +void RenderFillExtrusionLayer::transition(const TransitionParameters& parameters) { + unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated)); } void RenderFillExtrusionLayer::evaluate(const PropertyEvaluationParameters& parameters) { diff --git a/src/mbgl/renderer/render_fill_extrusion_layer.hpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp index bd66d8e3b1..1a55b56836 100644 --- a/src/mbgl/renderer/render_fill_extrusion_layer.hpp +++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp @@ -1,20 +1,17 @@ #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> 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; @@ -29,9 +26,9 @@ public: // Paint properties style::FillExtrusionPaintProperties::Unevaluated unevaluated; - style::FillExtrusionPaintProperties::Evaluated evaluated; + style::FillExtrusionPaintProperties::PossiblyEvaluated evaluated; - const style::FillExtrusionLayer::Impl* const impl; + const style::FillExtrusionLayer::Impl& impl() const; }; template <> diff --git a/src/mbgl/renderer/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp index 1af139cded..f1c7e97067 100644 --- a/src/mbgl/renderer/render_fill_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_layer.cpp @@ -1,5 +1,5 @@ -#include <mbgl/renderer/render_fill_layer.hpp> -#include <mbgl/renderer/fill_bucket.hpp> +#include <mbgl/renderer/layers/render_fill_layer.hpp> +#include <mbgl/renderer/buckets/fill_bucket.hpp> #include <mbgl/style/layers/fill_layer_impl.hpp> #include <mbgl/geometry/feature_index.hpp> #include <mbgl/util/math.hpp> @@ -7,21 +7,21 @@ namespace mbgl { -RenderFillLayer::RenderFillLayer(const style::FillLayer::Impl& _impl) - : RenderLayer(style::LayerType::Fill, _impl), - impl(&_impl) { +RenderFillLayer::RenderFillLayer(Immutable<style::FillLayer::Impl> _impl) + : RenderLayer(style::LayerType::Fill, _impl), + unevaluated(impl().paint.untransitioned()) { } -std::unique_ptr<RenderLayer> RenderFillLayer::clone() const { - return std::make_unique<RenderFillLayer>(*this); +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::cascade(const CascadeParameters& parameters) { - unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated)); +void RenderFillLayer::transition(const TransitionParameters& parameters) { + unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated)); } void RenderFillLayer::evaluate(const PropertyEvaluationParameters& parameters) { @@ -68,4 +68,4 @@ bool RenderFillLayer::queryIntersectsFeature( } -} +} // namespace mbgl diff --git a/src/mbgl/renderer/render_fill_layer.hpp b/src/mbgl/renderer/layers/render_fill_layer.hpp index 8080cf289b..1960fb653f 100644 --- a/src/mbgl/renderer/render_fill_layer.hpp +++ b/src/mbgl/renderer/layers/render_fill_layer.hpp @@ -1,20 +1,17 @@ #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; @@ -29,9 +26,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/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index 06c2564516..c27e5ea990 100644 --- a/src/mbgl/renderer/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -1,5 +1,5 @@ -#include <mbgl/renderer/render_line_layer.hpp> -#include <mbgl/renderer/line_bucket.hpp> +#include <mbgl/renderer/layers/render_line_layer.hpp> +#include <mbgl/renderer/buckets/line_bucket.hpp> #include <mbgl/style/layers/line_layer_impl.hpp> #include <mbgl/geometry/feature_index.hpp> #include <mbgl/util/math.hpp> @@ -7,34 +7,35 @@ namespace mbgl { -RenderLineLayer::RenderLineLayer(const style::LineLayer::Impl& _impl) - : RenderLayer(style::LayerType::Line, _impl), - impl(&_impl) { +RenderLineLayer::RenderLineLayer(Immutable<style::LineLayer::Impl> _impl) + : RenderLayer(style::LayerType::Line, _impl), + unevaluated(impl().paint.untransitioned()) { } -std::unique_ptr<RenderLayer> RenderLineLayer::clone() const { - return std::make_unique<RenderLineLayer>(*this); +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); + 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::transition(const TransitionParameters& parameters) { + unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated)); } void RenderLineLayer::evaluate(const PropertyEvaluationParameters& parameters) { - // for scaling dasharrays + style::Properties<LineFloorwidth>::Unevaluated extra(unevaluated.get<style::LineWidth>()); + auto dashArrayParams = parameters; - dashArrayParams.z = std::floor(dashArrayParams.z); - dashLineWidth = unevaluated.evaluate<style::LineWidth>(dashArrayParams); + dashArrayParams.useIntegerZoom = true; - evaluated = unevaluated.evaluate(parameters); + 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>() > 0) + && evaluated.get<style::LineWidth>().constantOr(1.0) > 0) ? RenderPass::Translucent : RenderPass::None; } @@ -103,7 +104,8 @@ bool RenderLineLayer::queryIntersectsFeature( } float RenderLineLayer::getLineWidth(const GeometryTileFeature& feature, const float zoom) const { - float lineWidth = evaluated.get<style::LineWidth>(); + 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) { diff --git a/src/mbgl/renderer/render_line_layer.hpp b/src/mbgl/renderer/layers/render_line_layer.hpp index 6d6fecc227..77551b6b7c 100644 --- a/src/mbgl/renderer/render_line_layer.hpp +++ b/src/mbgl/renderer/layers/render_line_layer.hpp @@ -1,20 +1,26 @@ #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; @@ -29,16 +35,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..84e27a3895 --- /dev/null +++ b/src/mbgl/renderer/layers/render_raster_layer.cpp @@ -0,0 +1,50 @@ +#include <mbgl/renderer/layers/render_raster_layer.hpp> +#include <mbgl/renderer/bucket.hpp> +#include <mbgl/style/layers/raster_layer_impl.hpp> +#include <mbgl/gl/context.hpp> +#include <mbgl/renderer/render_tile.hpp> +#include <mbgl/tile/tile.hpp> +#include <mbgl/renderer/sources/render_image_source.hpp> +#include <mbgl/renderer/painter.hpp> + +namespace mbgl { + +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(); +} + +void RenderRasterLayer::render(Painter& painter, PaintParameters& parameters, RenderSource* source) { + RenderLayer::render(painter, parameters, source); + if (renderTiles.empty()) { + RenderImageSource* imageSource = source->as<RenderImageSource>(); + if (imageSource) { + imageSource->render(painter, parameters, *this); + } + } +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/render_raster_layer.hpp b/src/mbgl/renderer/layers/render_raster_layer.hpp index 3ffeb8febf..ce46152a95 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(Painter&, 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/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 30d769e032..6540fc9612 100644 --- a/src/mbgl/renderer/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -1,4 +1,4 @@ -#include <mbgl/renderer/render_symbol_layer.hpp> +#include <mbgl/renderer/layers/render_symbol_layer.hpp> #include <mbgl/layout/symbol_layout.hpp> #include <mbgl/renderer/bucket.hpp> #include <mbgl/renderer/bucket_parameters.hpp> @@ -8,13 +8,13 @@ namespace mbgl { -RenderSymbolLayer::RenderSymbolLayer(const style::SymbolLayer::Impl& _impl) - : RenderLayer(style::LayerType::Symbol, _impl), - impl(&_impl) { +RenderSymbolLayer::RenderSymbolLayer(Immutable<style::SymbolLayer::Impl> _impl) + : RenderLayer(style::LayerType::Symbol, _impl), + unevaluated(impl().paint.untransitioned()) { } -std::unique_ptr<RenderLayer> RenderSymbolLayer::clone() const { - return std::make_unique<RenderSymbolLayer>(*this); +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 { @@ -24,18 +24,18 @@ std::unique_ptr<Bucket> RenderSymbolLayer::createBucket(const BucketParameters&, std::unique_ptr<SymbolLayout> RenderSymbolLayer::createLayout(const BucketParameters& parameters, const std::vector<const RenderLayer*>& group, - const GeometryTileLayer& layer, + std::unique_ptr<GeometryTileLayer> layer, GlyphDependencies& glyphDependencies, - IconDependencies& iconDependencies) const { + ImageDependencies& imageDependencies) const { return std::make_unique<SymbolLayout>(parameters, group, - layer, - iconDependencies, + std::move(layer), + imageDependencies, glyphDependencies); } -void RenderSymbolLayer::cascade(const CascadeParameters& parameters) { - unevaluated = impl->cascading.cascade(parameters, std::move(unevaluated)); +void RenderSymbolLayer::transition(const TransitionParameters& parameters) { + unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated)); } void RenderSymbolLayer::evaluate(const PropertyEvaluationParameters& parameters) { @@ -55,8 +55,8 @@ bool RenderSymbolLayer::hasTransition() const { return unevaluated.hasTransition(); } -style::IconPaintProperties::Evaluated RenderSymbolLayer::iconPaintProperties() const { - return style::IconPaintProperties::Evaluated { +style::IconPaintProperties::PossiblyEvaluated RenderSymbolLayer::iconPaintProperties() const { + return style::IconPaintProperties::PossiblyEvaluated { evaluated.get<style::IconOpacity>(), evaluated.get<style::IconColor>(), evaluated.get<style::IconHaloColor>(), @@ -67,8 +67,8 @@ style::IconPaintProperties::Evaluated RenderSymbolLayer::iconPaintProperties() c }; } -style::TextPaintProperties::Evaluated RenderSymbolLayer::textPaintProperties() const { - return style::TextPaintProperties::Evaluated { +style::TextPaintProperties::PossiblyEvaluated RenderSymbolLayer::textPaintProperties() const { + return style::TextPaintProperties::PossiblyEvaluated { evaluated.get<style::TextOpacity>(), evaluated.get<style::TextColor>(), evaluated.get<style::TextHaloColor>(), @@ -84,11 +84,8 @@ style::SymbolPropertyValues RenderSymbolLayer::iconPropertyValues(const style::S 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 @@ -99,11 +96,8 @@ style::SymbolPropertyValues RenderSymbolLayer::textPropertyValues(const style::S 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 diff --git a/src/mbgl/renderer/render_symbol_layer.hpp b/src/mbgl/renderer/layers/render_symbol_layer.hpp index 80ffd95a06..2199103de2 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,14 +40,10 @@ public: // Layout AlignmentType pitchAlignment; AlignmentType rotationAlignment; - PossiblyEvaluatedPropertyValue<float> layoutSize; // Paint std::array<float, 2> translate; TranslateAnchorType translateAnchor; - float paintSize; - - float sdfScale; // Constant (1.0 or 24.0) bool hasHalo; bool hasFill; @@ -61,33 +57,34 @@ 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; - 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_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp index bcbc7c287d..f78147fc87 100644 --- a/src/mbgl/renderer/paint_property_binder.hpp +++ b/src/mbgl/renderer/paint_property_binder.hpp @@ -4,6 +4,7 @@ #include <mbgl/gl/attribute.hpp> #include <mbgl/gl/uniform.hpp> #include <mbgl/util/type_list.hpp> +#include <mbgl/renderer/possibly_evaluated_property_value.hpp> #include <mbgl/renderer/paint_property_statistics.hpp> #include <bitset> @@ -102,11 +103,8 @@ public: void populateVertexVector(const GeometryTileFeature&, std::size_t) override {} void upload(gl::Context&) override {} - AttributeBinding attributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override { - auto value = attributeValue(currentValue.constantOr(constant)); - return typename Attribute::ConstantBinding { - zoomInterpolatedAttributeValue(value, value) - }; + AttributeBinding attributeBinding(const PossiblyEvaluatedPropertyValue<T>&) const override { + return gl::DisabledAttribute(); } float interpolationFactor(float) const override { @@ -151,12 +149,9 @@ public: AttributeBinding attributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override { if (currentValue.isConstant()) { - BaseAttributeValue value = attributeValue(*currentValue.constant()); - return typename Attribute::ConstantBinding { - zoomInterpolatedAttributeValue(value, value) - }; + return gl::DisabledAttribute(); } else { - return Attribute::variableBinding(*vertexBuffer, 0, BaseAttribute::Dimensions); + return Attribute::binding(*vertexBuffer, 0, BaseAttribute::Dimensions); } } @@ -215,17 +210,18 @@ public: AttributeBinding attributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const override { if (currentValue.isConstant()) { - BaseAttributeValue value = attributeValue(*currentValue.constant()); - return typename Attribute::ConstantBinding { - zoomInterpolatedAttributeValue(value, value) - }; + return gl::DisabledAttribute(); } else { - return Attribute::variableBinding(*vertexBuffer, 0); + return Attribute::binding(*vertexBuffer, 0); } } 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 index da4903864b..47db8254e2 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -2,6 +2,7 @@ #include <mbgl/renderer/paint_parameters.hpp> #include <mbgl/renderer/render_tile.hpp> #include <mbgl/renderer/render_source.hpp> +#include <mbgl/renderer/render_style.hpp> #include <mbgl/style/source.hpp> #include <mbgl/style/source_impl.hpp> @@ -11,25 +12,21 @@ #include <mbgl/util/logging.hpp> #include <mbgl/gl/debugging.hpp> -#include <mbgl/style/style.hpp> #include <mbgl/style/layer_impl.hpp> +#include <mbgl/style/layers/custom_layer_impl.hpp> #include <mbgl/tile/tile.hpp> -#include <mbgl/renderer/render_background_layer.hpp> -#include <mbgl/renderer/render_custom_layer.hpp> +#include <mbgl/renderer/layers/render_background_layer.hpp> +#include <mbgl/renderer/layers/render_custom_layer.hpp> #include <mbgl/style/layers/custom_layer_impl.hpp> -#include <mbgl/renderer/render_fill_extrusion_layer.hpp> +#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp> -#include <mbgl/sprite/sprite_atlas.hpp> +#include <mbgl/renderer/image_manager.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> @@ -118,14 +115,14 @@ Painter::Painter(gl::Context& context_, Painter::~Painter() = default; bool Painter::needsAnimation() const { - return frameHistory.needsAnimation(util::DEFAULT_FADE_DURATION); + return frameHistory.needsAnimation(util::DEFAULT_TRANSITION_DURATION); } void Painter::cleanup() { context.performCleanup(); } -void Painter::render(const Style& style, const FrameData& frame_, View& view, SpriteAtlas& annotationSpriteAtlas) { +void Painter::render(RenderStyle& style, const FrameData& frame_, View& view) { frame = frame_; if (frame.contextMode == GLContextMode::Shared) { context.setDirtyState(); @@ -140,11 +137,10 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp view }; - glyphAtlas = style.glyphAtlas.get(); - spriteAtlas = style.spriteAtlas.get(); + imageManager = style.imageManager.get(); lineAtlas = style.lineAtlas.get(); - evaluatedLight = style.getRenderLight()->getEvaluated(); + evaluatedLight = style.getRenderLight().getEvaluated(); RenderData renderData = style.getRenderData(frame.debugOptions, state.getAngle()); const std::vector<RenderItem>& order = renderData.order; @@ -163,7 +159,7 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp } frameHistory.record(frame.timePoint, state.getZoom(), - frame.mapMode == MapMode::Continuous ? util::DEFAULT_FADE_DURATION : Milliseconds(0)); + frame.mapMode == MapMode::Continuous ? util::DEFAULT_TRANSITION_DURATION : Milliseconds(0)); // - UPLOAD PASS ------------------------------------------------------------------------------- @@ -171,21 +167,9 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp { MBGL_DEBUG_GROUP(context, "upload"); - spriteAtlas->upload(context, 0); - + imageManager->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 ------------------------------------------------------------------------------------- @@ -207,14 +191,14 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp MBGL_DEBUG_GROUP(context, "clip"); // Update all clipping IDs. - algorithm::ClipIDGenerator generator; + clipIDGenerator = algorithm::ClipIDGenerator(); for (const auto& source : sources) { - source->startRender(generator, projMatrix, nearClippedProjMatrix, state); + source->startRender(*this); } MBGL_DEBUG_GROUP(context, "clipping masks"); - for (const auto& stencil : generator.getStencils()) { + for (const auto& stencil : clipIDGenerator.getStencils()) { MBGL_DEBUG_GROUP(context, std::string{ "mask: " } + util::toString(stencil.first)); renderClippingMask(stencil.first, stencil.second); } @@ -308,21 +292,6 @@ void Painter::renderPass(PaintParameters& parameters, 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.vertexArrayObject = 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; @@ -336,13 +305,7 @@ void Painter::renderPass(PaintParameters& parameters, 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); - } + renderItem(parameters, item); parameters.view.bind(); context.bindTexture(extrusionTexture->getTexture()); @@ -350,7 +313,7 @@ void Painter::renderPass(PaintParameters& parameters, mat4 viewportMat; matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1); - const PaintProperties<>::Evaluated properties{}; + const Properties<>::PossiblyEvaluated properties; parameters.programs.extrusionTexture.draw( context, gl::Triangles(), gl::DepthMode::disabled(), gl::StencilMode::disabled(), @@ -364,12 +327,7 @@ void Painter::renderPass(PaintParameters& parameters, ExtrusionTextureProgram::PaintPropertyBinders{ properties, 0 }, properties, state.getZoom()); } 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); - } + renderItem(parameters, item); } } @@ -378,6 +336,12 @@ void Painter::renderPass(PaintParameters& parameters, } } +void Painter::renderItem(PaintParameters& parameters, const RenderItem& item) { + RenderLayer& layer = item.layer; + MBGL_DEBUG_GROUP(context, layer.getID()); + layer.render(*this, parameters, item.source); +} + mat4 Painter::matrixForTile(const UnwrappedTileID& tileID) { mat4 matrix; state.matrixFor(matrix, tileID); diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp index 4658f0c206..7e966adefa 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -7,6 +7,7 @@ #include <mbgl/renderer/frame_history.hpp> #include <mbgl/renderer/render_item.hpp> #include <mbgl/renderer/bucket.hpp> +#include <mbgl/renderer/render_light.hpp> #include <mbgl/gl/context.hpp> #include <mbgl/programs/debug_program.hpp> @@ -15,13 +16,13 @@ #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 <mbgl/algorithm/generate_clip_ids.hpp> + #include <array> #include <vector> #include <set> @@ -29,10 +30,10 @@ namespace mbgl { +class RenderStyle; class RenderTile; -class SpriteAtlas; +class ImageManager; class View; -class GlyphAtlas; class LineAtlas; struct FrameData; class Tile; @@ -59,11 +60,6 @@ class TilePyramid; struct ClipID; -namespace style { -class Style; -class Source; -} // namespace style - struct FrameData { TimePoint timePoint; float pixelRatio; @@ -77,23 +73,25 @@ public: Painter(gl::Context&, const TransformState&, float pixelRatio, const optional<std::string>& programCacheDir); ~Painter(); - void render(const style::Style&, + void render(RenderStyle&, const FrameData&, - View&, - SpriteAtlas& annotationSpriteAtlas); + View&); void cleanup(); void renderClippingMask(const UnwrappedTileID&, const ClipID&); void renderTileDebug(const RenderTile&); + void renderTileDebug(const mat4& matrix); 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 renderRaster(PaintParameters&, RasterBucket&, const RenderRasterLayer&, const mat4&, bool useBucketBuffers /* = false */); void renderBackground(PaintParameters&, const RenderBackgroundLayer&); + void renderItem(PaintParameters&, const RenderItem&); + #ifndef NDEBUG // Renders tile clip boundaries, using stencil buffer to calculate fill color. void renderClipMasks(PaintParameters&); @@ -103,9 +101,6 @@ public: bool needsAnimation() const; -private: - std::vector<RenderItem> determineRenderOrder(const style::Style&); - template <class Iterator> void renderPass(PaintParameters&, RenderPass, @@ -128,9 +123,10 @@ private: } #endif -private: gl::Context& context; + algorithm::ClipIDGenerator clipIDGenerator; + mat4 projMatrix; mat4 nearClippedProjMatrix; @@ -155,8 +151,7 @@ private: float depthRangeSize; const float depthEpsilon = 1.0f / (1 << 16); - SpriteAtlas* spriteAtlas = nullptr; - GlyphAtlas* glyphAtlas = nullptr; + ImageManager* imageManager = nullptr; LineAtlas* lineAtlas = nullptr; optional<OffscreenTexture> extrusionTexture; diff --git a/src/mbgl/renderer/painter_background.cpp b/src/mbgl/renderer/painters/painter_background.cpp index d01696ee3e..577d7d6cda 100644 --- a/src/mbgl/renderer/painter_background.cpp +++ b/src/mbgl/renderer/painters/painter_background.cpp @@ -1,10 +1,10 @@ #include <mbgl/renderer/painter.hpp> #include <mbgl/renderer/paint_parameters.hpp> -#include <mbgl/renderer/render_background_layer.hpp> +#include <mbgl/renderer/layers/render_background_layer.hpp> +#include <mbgl/renderer/image_manager.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 { @@ -14,9 +14,9 @@ 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; + const BackgroundPaintProperties::PossiblyEvaluated& background = layer.evaluated; - style::FillPaintProperties::Evaluated properties; + style::FillPaintProperties::PossiblyEvaluated properties; properties.get<FillPattern>() = background.get<BackgroundPattern>(); properties.get<FillOpacity>() = { background.get<BackgroundOpacity>() }; properties.get<FillColor>() = { background.get<BackgroundColor>() }; @@ -24,13 +24,13 @@ void Painter::renderBackground(PaintParameters& parameters, const RenderBackgrou 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); + optional<ImagePosition> imagePosA = imageManager->getPattern(background.get<BackgroundPattern>().from); + optional<ImagePosition> imagePosB = imageManager->getPattern(background.get<BackgroundPattern>().to); if (!imagePosA || !imagePosB) return; - spriteAtlas->bind(true, context, 0); + imageManager->bind(context, 0); for (const auto& tileID : util::tileCover(state, state.getIntegerZoom())) { parameters.programs.fillPattern.get(properties).draw( @@ -42,6 +42,7 @@ void Painter::renderBackground(PaintParameters& parameters, const RenderBackgrou FillPatternUniforms::values( matrixForTile(tileID), context.viewport.getCurrentValue().size, + imageManager->getPixelSize(), *imagePosA, *imagePosB, background.get<BackgroundPattern>(), diff --git a/src/mbgl/renderer/painter_circle.cpp b/src/mbgl/renderer/painters/painter_circle.cpp index 13acb5f7fe..58e384979d 100644 --- a/src/mbgl/renderer/painter_circle.cpp +++ b/src/mbgl/renderer/painters/painter_circle.cpp @@ -1,8 +1,8 @@ #include <mbgl/renderer/painter.hpp> #include <mbgl/renderer/paint_parameters.hpp> -#include <mbgl/renderer/circle_bucket.hpp> +#include <mbgl/renderer/buckets/circle_bucket.hpp> #include <mbgl/renderer/render_tile.hpp> -#include <mbgl/renderer/render_circle_layer.hpp> +#include <mbgl/renderer/layers/render_circle_layer.hpp> #include <mbgl/style/layers/circle_layer_impl.hpp> #include <mbgl/programs/programs.hpp> #include <mbgl/programs/circle_program.hpp> @@ -20,7 +20,7 @@ void Painter::renderCircle(PaintParameters& parameters, return; } - const CirclePaintProperties::Evaluated& properties = layer.evaluated; + const CirclePaintProperties::PossiblyEvaluated& properties = layer.evaluated; const bool scaleWithMap = properties.get<CirclePitchScale>() == CirclePitchScaleType::Map; parameters.programs.circle.get(properties).draw( diff --git a/src/mbgl/renderer/painter_clipping.cpp b/src/mbgl/renderer/painters/painter_clipping.cpp index b3a2d77b1a..cad092594e 100644 --- a/src/mbgl/renderer/painter_clipping.cpp +++ b/src/mbgl/renderer/painters/painter_clipping.cpp @@ -6,7 +6,7 @@ namespace mbgl { void Painter::renderClippingMask(const UnwrappedTileID& tileID, const ClipID& clip) { - static const style::FillPaintProperties::Evaluated properties {}; + static const style::FillPaintProperties::PossiblyEvaluated properties {}; static const FillProgram::PaintPropertyBinders paintAttibuteData(properties, 0); programs->fill.get(properties).draw( context, diff --git a/src/mbgl/renderer/painter_debug.cpp b/src/mbgl/renderer/painters/painter_debug.cpp index 37fa3bcb12..ee76aee54c 100644 --- a/src/mbgl/renderer/painter_debug.cpp +++ b/src/mbgl/renderer/painters/painter_debug.cpp @@ -1,5 +1,5 @@ #include <mbgl/renderer/painter.hpp> -#include <mbgl/renderer/debug_bucket.hpp> +#include <mbgl/renderer/buckets/debug_bucket.hpp> #include <mbgl/renderer/render_tile.hpp> #include <mbgl/renderer/paint_parameters.hpp> #include <mbgl/map/view.hpp> @@ -20,7 +20,7 @@ void Painter::renderTileDebug(const RenderTile& renderTile) { MBGL_DEBUG_GROUP(context, std::string { "debug " } + util::toString(renderTile.id)); - static const style::PaintProperties<>::Evaluated properties {}; + static const style::Properties<>::PossiblyEvaluated properties {}; static const DebugProgram::PaintPropertyBinders paintAttibuteData(properties, 0); auto draw = [&] (Color color, const auto& vertexBuffer, const auto& indexBuffer, const auto& segments, auto drawMode) { @@ -77,6 +77,34 @@ void Painter::renderTileDebug(const RenderTile& renderTile) { } } +void Painter::renderTileDebug(const mat4& matrix) { + if (frame.debugOptions == MapDebugOptions::NoDebug) + return; + + static const style::Properties<>::PossiblyEvaluated properties {}; + static const DebugProgram::PaintPropertyBinders paintAttibuteData(properties, 0); + + if (frame.debugOptions & MapDebugOptions::TileBorders) { + programs->debug.draw( + context, + gl::LineStrip { 4.0f * frame.pixelRatio }, + gl::DepthMode::disabled(), + gl::StencilMode::disabled(), + gl::ColorMode::unblended(), + DebugProgram::UniformValues { + uniforms::u_matrix::Value{ matrix }, + uniforms::u_color::Value{ Color::red() } + }, + tileVertexBuffer, + tileBorderIndexBuffer, + tileBorderSegments, + paintAttibuteData, + properties, + state.getZoom() + ); + } +} + #ifndef NDEBUG void Painter::renderClipMasks(PaintParameters&) { context.setStencilMode(gl::StencilMode::disabled()); diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painters/painter_fill.cpp index e1b59d8839..3a0bfed454 100644 --- a/src/mbgl/renderer/painter_fill.cpp +++ b/src/mbgl/renderer/painters/painter_fill.cpp @@ -1,10 +1,10 @@ #include <mbgl/renderer/painter.hpp> #include <mbgl/renderer/paint_parameters.hpp> -#include <mbgl/renderer/fill_bucket.hpp> +#include <mbgl/renderer/buckets/fill_bucket.hpp> #include <mbgl/renderer/render_tile.hpp> -#include <mbgl/renderer/render_fill_layer.hpp> +#include <mbgl/renderer/layers/render_fill_layer.hpp> +#include <mbgl/renderer/image_manager.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> @@ -17,21 +17,21 @@ void Painter::renderFill(PaintParameters& parameters, FillBucket& bucket, const RenderFillLayer& layer, const RenderTile& tile) { - const FillPaintProperties::Evaluated& properties = layer.evaluated; + const FillPaintProperties::PossiblyEvaluated& 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); + optional<ImagePosition> imagePosA = imageManager->getPattern(properties.get<FillPattern>().from); + optional<ImagePosition> imagePosB = imageManager->getPattern(properties.get<FillPattern>().to); if (!imagePosA || !imagePosB) { return; } - spriteAtlas->bind(true, context, 0); + imageManager->bind(context, 0); auto draw = [&] (uint8_t sublayer, auto& program, @@ -49,6 +49,7 @@ void Painter::renderFill(PaintParameters& parameters, properties.get<FillTranslateAnchor>(), state), context.viewport.getCurrentValue().size, + imageManager->getPixelSize(), *imagePosA, *imagePosB, properties.get<FillPattern>(), diff --git a/src/mbgl/renderer/painter_fill_extrusion.cpp b/src/mbgl/renderer/painters/painter_fill_extrusion.cpp index 95617525c7..165476944b 100644 --- a/src/mbgl/renderer/painter_fill_extrusion.cpp +++ b/src/mbgl/renderer/painters/painter_fill_extrusion.cpp @@ -1,10 +1,10 @@ #include <mbgl/renderer/painter.hpp> #include <mbgl/renderer/paint_parameters.hpp> -#include <mbgl/renderer/fill_extrusion_bucket.hpp> +#include <mbgl/renderer/buckets/fill_extrusion_bucket.hpp> #include <mbgl/renderer/render_tile.hpp> -#include <mbgl/renderer/render_fill_extrusion_layer.hpp> +#include <mbgl/renderer/layers/render_fill_extrusion_layer.hpp> +#include <mbgl/renderer/image_manager.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> @@ -18,23 +18,21 @@ void Painter::renderFillExtrusion(PaintParameters& parameters, FillExtrusionBucket& bucket, const RenderFillExtrusionLayer& layer, const RenderTile& tile) { - const FillExtrusionPaintProperties::Evaluated& properties = layer.evaluated; + const FillExtrusionPaintProperties::PossiblyEvaluated& 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); + optional<ImagePosition> imagePosA = imageManager->getPattern(properties.get<FillExtrusionPattern>().from); + optional<ImagePosition> imagePosB = imageManager->getPattern(properties.get<FillExtrusionPattern>().to); if (!imagePosA || !imagePosB) { return; } - spriteAtlas->bind(true, context, 0); + imageManager->bind(context, 0); parameters.programs.fillExtrusionPattern.get(properties).draw( context, @@ -46,6 +44,7 @@ void Painter::renderFillExtrusion(PaintParameters& parameters, tile.translatedClipMatrix(properties.get<FillExtrusionTranslate>(), properties.get<FillExtrusionTranslateAnchor>(), state), + imageManager->getPixelSize(), *imagePosA, *imagePosB, properties.get<FillExtrusionPattern>(), diff --git a/src/mbgl/renderer/painter_line.cpp b/src/mbgl/renderer/painters/painter_line.cpp index 9152ac8512..58f4131d96 100644 --- a/src/mbgl/renderer/painter_line.cpp +++ b/src/mbgl/renderer/painters/painter_line.cpp @@ -1,12 +1,12 @@ #include <mbgl/renderer/painter.hpp> #include <mbgl/renderer/paint_parameters.hpp> -#include <mbgl/renderer/line_bucket.hpp> +#include <mbgl/renderer/buckets/line_bucket.hpp> #include <mbgl/renderer/render_tile.hpp> -#include <mbgl/renderer/render_line_layer.hpp> +#include <mbgl/renderer/layers/render_line_layer.hpp> +#include <mbgl/renderer/image_manager.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 { @@ -21,7 +21,7 @@ void Painter::renderLine(PaintParameters& parameters, return; } - const LinePaintProperties::Evaluated& properties = layer.evaluated; + const RenderLinePaintProperties::PossiblyEvaluated& properties = layer.evaluated; auto draw = [&] (auto& program, auto&& uniformValues) { program.get(properties).draw( @@ -57,17 +57,16 @@ void Painter::renderLine(PaintParameters& parameters, 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); + optional<ImagePosition> posA = imageManager->getPattern(properties.get<LinePattern>().from); + optional<ImagePosition> posB = imageManager->getPattern(properties.get<LinePattern>().to); if (!posA || !posB) return; - spriteAtlas->bind(true, context, 0); + imageManager->bind(context, 0); draw(parameters.programs.linePattern, LinePatternProgram::uniformValues( @@ -75,6 +74,7 @@ void Painter::renderLine(PaintParameters& parameters, tile, state, pixelsToGLUnits, + imageManager->getPixelSize(), *posA, *posB)); diff --git a/src/mbgl/renderer/painter_raster.cpp b/src/mbgl/renderer/painters/painter_raster.cpp index fbe025b5b0..56e38ae8f4 100644 --- a/src/mbgl/renderer/painter_raster.cpp +++ b/src/mbgl/renderer/painters/painter_raster.cpp @@ -1,8 +1,8 @@ #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/renderer/buckets/raster_bucket.hpp> +#include <mbgl/renderer/layers/render_raster_layer.hpp> #include <mbgl/style/layers/raster_layer_impl.hpp> #include <mbgl/programs/programs.hpp> #include <mbgl/programs/raster_program.hpp> @@ -42,13 +42,14 @@ static std::array<float, 3> spinWeights(float spin) { void Painter::renderRaster(PaintParameters& parameters, RasterBucket& bucket, const RenderRasterLayer& layer, - const RenderTile& tile) { + const mat4& matrix, + bool useBucketBuffers = false) { if (pass != RenderPass::Translucent) return; if (!bucket.hasData()) return; - const RasterPaintProperties::Evaluated& properties = layer.evaluated; + const RasterPaintProperties::PossiblyEvaluated& properties = layer.evaluated; const RasterProgram::PaintPropertyBinders paintAttributeData(properties, 0); assert(bucket.texture); @@ -62,7 +63,7 @@ void Painter::renderRaster(PaintParameters& parameters, gl::StencilMode::disabled(), colorModeForRenderPass(), RasterProgram::UniformValues { - uniforms::u_matrix::Value{ tile.matrix }, + uniforms::u_matrix::Value{ matrix }, uniforms::u_image0::Value{ 0 }, uniforms::u_image1::Value{ 1 }, uniforms::u_opacity::Value{ properties.get<RasterOpacity>() }, @@ -76,9 +77,9 @@ void Painter::renderRaster(PaintParameters& parameters, uniforms::u_scale_parent::Value{ 1.0f }, uniforms::u_tl_parent::Value{ std::array<float, 2> {{ 0.0f, 0.0f }} }, }, - rasterVertexBuffer, - quadTriangleIndexBuffer, - rasterSegments, + useBucketBuffers ? *bucket.vertexBuffer : rasterVertexBuffer, + useBucketBuffers ? *bucket.indexBuffer : quadTriangleIndexBuffer, + useBucketBuffers ? bucket.segments : rasterSegments, paintAttributeData, properties, state.getZoom() diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painters/painter_symbol.cpp index 86b2146b9f..d3a505aa3f 100644 --- a/src/mbgl/renderer/painter_symbol.cpp +++ b/src/mbgl/renderer/painters/painter_symbol.cpp @@ -1,16 +1,15 @@ #include <mbgl/renderer/painter.hpp> #include <mbgl/renderer/paint_parameters.hpp> -#include <mbgl/renderer/symbol_bucket.hpp> +#include <mbgl/renderer/buckets/symbol_bucket.hpp> #include <mbgl/renderer/render_tile.hpp> -#include <mbgl/renderer/render_symbol_layer.hpp> +#include <mbgl/renderer/layers/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 <mbgl/tile/geometry_tile.hpp> #include <cmath> @@ -54,7 +53,6 @@ void Painter::renderSymbol(PaintParameters& parameters, std::move(uniformValues), *buffers.vertexBuffer, *symbolSizeBinder, - values_.layoutSize, *buffers.indexBuffer, buffers.segments, binders, @@ -63,18 +61,21 @@ void Painter::renderSymbol(PaintParameters& parameters, ); }; + assert(dynamic_cast<GeometryTile*>(&tile.tile)); + GeometryTile& geometryTile = static_cast<GeometryTile&>(tile.tile); + 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 iconScaled = layout.get<IconSize>().constantOr(1.0) != 1.0 || 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(); + context.bindTexture(*geometryTile.iconAtlasTexture, 0, + bucket.sdfIcons || state.isChanging() || iconScaled || iconTransformed + ? gl::TextureFilter::Linear : gl::TextureFilter::Nearest); + + const Size texsize = geometryTile.iconAtlasTexture->size; if (bucket.sdfIcons) { if (values.hasHalo) { @@ -108,12 +109,12 @@ void Painter::renderSymbol(PaintParameters& parameters, } if (bucket.hasTextData()) { - glyphAtlas->bind(context, 0); + context.bindTexture(*geometryTile.glyphAtlasTexture, 0, gl::TextureFilter::Linear); auto values = layer.textPropertyValues(layout); auto paintPropertyValues = layer.textPaintProperties(); - const Size texsize = glyphAtlas->getSize(); + const Size texsize = geometryTile.glyphAtlasTexture->size; if (values.hasHalo) { draw(parameters.programs.symbolGlyph, @@ -137,7 +138,7 @@ void Painter::renderSymbol(PaintParameters& parameters, } if (bucket.hasCollisionBoxData()) { - static const style::PaintProperties<>::Evaluated properties {}; + static const style::Properties<>::PossiblyEvaluated properties {}; static const CollisionBoxProgram::PaintPropertyBinders paintAttributeData(properties, 0); programs->collisionBox.draw( diff --git a/src/mbgl/renderer/possibly_evaluated_property_value.hpp b/src/mbgl/renderer/possibly_evaluated_property_value.hpp index a0bcec2bf1..8a5dfbe4ea 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>(); @@ -48,10 +50,16 @@ public: 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_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_item.hpp b/src/mbgl/renderer/render_item.hpp index 787211c30a..4bf5629263 100644 --- a/src/mbgl/renderer/render_item.hpp +++ b/src/mbgl/renderer/render_item.hpp @@ -17,13 +17,13 @@ namespace style { class RenderItem { public: - RenderItem(const RenderLayer& layer_, - std::vector<std::reference_wrapper<RenderTile>> tiles_ = {}) - : layer(layer_), tiles(std::move(tiles_)) { + RenderItem(RenderLayer& layer_, + RenderSource* renderSource_) + : layer(layer_), source(renderSource_) { } - const RenderLayer& layer; - std::vector<std::reference_wrapper<RenderTile>> tiles; + RenderLayer& layer; + RenderSource* source; }; class RenderData { diff --git a/src/mbgl/renderer/render_layer.cpp b/src/mbgl/renderer/render_layer.cpp index 6699f39144..3f9d68003e 100644 --- a/src/mbgl/renderer/render_layer.cpp +++ b/src/mbgl/renderer/render_layer.cpp @@ -1,14 +1,56 @@ #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> +#include <mbgl/tile/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 +59,23 @@ 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; } -}
\ No newline at end of file +void RenderLayer::setRenderTiles(std::vector<std::reference_wrapper<RenderTile>> tiles) { + renderTiles = std::move(tiles); +} + +void RenderLayer::render(Painter& painter, PaintParameters& parameters, RenderSource*) { + for (auto& tileRef : renderTiles) { + auto& tile = tileRef.get(); + auto bucket = tile.tile.getBucket(*baseImpl); + bucket->render(painter, parameters, *this, tile); + } +} + + +} //namespace mbgl + diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp index eea2ec1f61..e06f479281 100644 --- a/src/mbgl/renderer/render_layer.hpp +++ b/src/mbgl/renderer/render_layer.hpp @@ -12,27 +12,28 @@ namespace mbgl { class Bucket; class BucketParameters; -class CascadeParameters; +class TransitionParameters; class PropertyEvaluationParameters; +class Painter; +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 +62,8 @@ public: // Checks whether this layer can be rendered. bool needsRendering(float zoom) const; + virtual void render(Painter&, PaintParameters&, RenderSource*); + // Check wether the given geometry intersects // with the feature virtual bool queryIntersectsFeature( @@ -72,15 +75,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_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..b82547b375 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> @@ -17,41 +18,43 @@ namespace mbgl { class Painter; class TransformState; class RenderTile; +class RenderStyle; +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 startRender(Painter&) = 0; virtual void finishRender(Painter&) = 0; virtual std::map<UnwrappedTileID, RenderTile>& getRenderTiles() = 0; @@ -59,24 +62,26 @@ public: virtual std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, + const RenderStyle& style, 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_style.cpp b/src/mbgl/renderer/render_style.cpp new file mode 100644 index 0000000000..91efb6c737 --- /dev/null +++ b/src/mbgl/renderer/render_style.cpp @@ -0,0 +1,450 @@ +#include <mbgl/renderer/render_style.hpp> +#include <mbgl/renderer/render_style_observer.hpp> +#include <mbgl/renderer/update_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_source.hpp> +#include <mbgl/renderer/render_item.hpp> +#include <mbgl/renderer/render_tile.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/renderer/style_diff.hpp> +#include <mbgl/renderer/image_manager.hpp> +#include <mbgl/style/style.hpp> +#include <mbgl/style/source_impl.hpp> +#include <mbgl/style/transition_options.hpp> +#include <mbgl/sprite/sprite_loader.hpp> +#include <mbgl/text/glyph_manager.hpp> +#include <mbgl/geometry/line_atlas.hpp> +#include <mbgl/map/backend_scope.hpp> +#include <mbgl/map/query.hpp> +#include <mbgl/tile/tile.hpp> +#include <mbgl/util/math.hpp> +#include <mbgl/util/string.hpp> + +namespace mbgl { + +using namespace style; + +RenderStyleObserver nullObserver; + +RenderStyle::RenderStyle(Scheduler& scheduler_, FileSource& fileSource_) + : scheduler(scheduler_), + fileSource(fileSource_), + 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>()), + observer(&nullObserver) { + glyphManager->setObserver(this); +} + +RenderStyle::~RenderStyle() { + assert(BackendScope::exists()); // Required for custom layers. +} + +void RenderStyle::setObserver(RenderStyleObserver* observer_) { + observer = observer_; +} + +std::vector<const RenderLayer*> RenderStyle::getRenderLayers() const { + std::vector<const RenderLayer*> result; + result.reserve(renderLayers.size()); + for (const auto& layer : *layerImpls) { + result.push_back(getRenderLayer(layer->id)); + } + return result; +} + +RenderLayer* RenderStyle::getRenderLayer(const std::string& id) { + auto it = renderLayers.find(id); + return it != renderLayers.end() ? it->second.get() : nullptr; +} + +const RenderLayer* RenderStyle::getRenderLayer(const std::string& id) const { + auto it = renderLayers.find(id); + return it != renderLayers.end() ? it->second.get() : nullptr; +} + +const RenderLight& RenderStyle::getRenderLight() const { + return renderLight; +} + +void RenderStyle::update(const UpdateParameters& parameters) { + assert(BackendScope::exists()); // Required for custom layers. + + const bool zoomChanged = zoomHistory.update(parameters.transformState.getZoom(), parameters.timePoint); + + const TransitionParameters transitionParameters { + parameters.timePoint, + parameters.mode == MapMode::Continuous ? parameters.transitionOptions : TransitionOptions() + }; + + const PropertyEvaluationParameters evaluationParameters { + zoomHistory, + parameters.timePoint, + parameters.mode == MapMode::Continuous ? util::DEFAULT_TRANSITION_DURATION : Duration::zero() + }; + + const TileParameters tileParameters { + parameters.pixelRatio, + parameters.debugOptions, + parameters.transformState, + parameters.scheduler, + parameters.fileSource, + parameters.mode, + parameters.annotationManager, + *imageManager, + *glyphManager + }; + + glyphManager->setURL(parameters.glyphURL); + + // Update light. + const bool lightChanged = renderLight.impl != parameters.light; + + if (lightChanged) { + renderLight.impl = parameters.light; + renderLight.transition(transitionParameters); + } + + if (lightChanged || zoomChanged || renderLight.hasTransition()) { + renderLight.evaluate(evaluationParameters); + } + + + const ImageDifference imageDiff = diffImages(imageImpls, parameters.images); + imageImpls = parameters.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); + } + + if (parameters.spriteLoaded && !imageManager->isLoaded()) { + imageManager->onSpriteLoaded(); + } + + + const LayerDifference layerDiff = diffLayers(layerImpls, parameters.layers); + layerImpls = parameters.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, parameters.sources); + sourceImpls = parameters.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)); + } + + // 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 && ( + hasLayoutDifference(layerDiff, layer->id) || + !imageDiff.added.empty() || + !imageDiff.removed.empty() || + !imageDiff.changed.empty())) { + needsRelayout = true; + } + + filteredLayers.push_back(layer); + } + + renderSources.at(source->id)->update(source, + filteredLayers, + needsRendering, + needsRelayout, + tileParameters); + } +} + +RenderSource* RenderStyle::getRenderSource(const std::string& id) const { + auto it = renderSources.find(id); + return it != renderSources.end() ? it->second.get() : nullptr; +} + +bool RenderStyle::hasTransitions() const { + if (renderLight.hasTransition()) { + return true; + } + + for (const auto& entry : renderLayers) { + if (entry.second->hasTransition()) { + return true; + } + } + + return false; +} + +bool RenderStyle::isLoaded() const { + for (const auto& entry: renderSources) { + if (!entry.second->isLoaded()) { + return false; + } + } + + if (!imageManager->isLoaded()) { + return false; + } + + return true; +} + +RenderData RenderStyle::getRenderData(MapDebugOptions debugOptions, float angle) { + RenderData result; + + for (const auto& entry : renderSources) { + if (entry.second->isEnabled()) { + result.sources.insert(entry.second.get()); + } + } + + for (auto& layerImpl : *layerImpls) { + RenderLayer* layer = getRenderLayer(layerImpl->id); + assert(layer); + + if (!layer->needsRendering(zoomHistory.lastZoom)) { + continue; + } + + if (const RenderBackgroundLayer* background = layer->as<RenderBackgroundLayer>()) { + if (debugOptions & MapDebugOptions::Overdraw) { + // We want to skip glClear optimization in overdraw mode. + result.order.emplace_back(*layer, nullptr); + continue; + } + 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(). + result.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. + result.order.emplace_back(*layer, nullptr); + } + continue; + } + + if (layer->is<RenderCustomLayer>()) { + result.order.emplace_back(*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; + } + + auto& renderTiles = source->getRenderTiles(); + const bool symbolLayer = layer->is<RenderSymbolLayer>(); + + // 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::vector<std::reference_wrapper<RenderTile>> sortedTiles; + std::transform(renderTiles.begin(), renderTiles.end(), std::back_inserter(sortedTiles), + [](auto& pair) { return std::ref(pair.second); }); + if (symbolLayer) { + std::sort(sortedTiles.begin(), sortedTiles.end(), + [angle](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, angle); + auto pbr = util::rotate(pb, angle); + + return std::tie(par.y, par.x) < std::tie(pbr.y, pbr.x); + }); + } + + 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)); + result.order.emplace_back(*layer, source); + } + + return result; +} + +std::vector<Feature> RenderStyle::queryRenderedFeatures(const ScreenLineString& geometry, + const TransformState& transformState, + const RenderedQueryOptions& options) const { + std::unordered_map<std::string, std::vector<Feature>> resultsByLayer; + + if (options.layerIDs) { + std::unordered_set<std::string> sourceIDs; + for (const auto& layerID : *options.layerIDs) { + if (const RenderLayer* layer = getRenderLayer(layerID)) { + sourceIDs.emplace(layer->baseImpl->source); + } + } + for (const auto& sourceID : sourceIDs) { + if (RenderSource* renderSource = getRenderSource(sourceID)) { + auto sourceResults = renderSource->queryRenderedFeatures(geometry, transformState, *this, options); + std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin())); + } + } + } else { + for (const auto& entry : renderSources) { + auto sourceResults = entry.second->queryRenderedFeatures(geometry, transformState, *this, 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; +} + +void RenderStyle::onLowMemory() { + for (const auto& entry : renderSources) { + entry.second->onLowMemory(); + } +} + +void RenderStyle::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 RenderStyle::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 RenderStyle::onTileChanged(RenderSource&, const OverscaledTileID&) { + observer->onInvalidate(); +} + +void RenderStyle::dumpDebugLogs() const { + for (const auto& entry : renderSources) { + entry.second->dumpDebugLogs(); + } + + imageManager->dumpDebugLogs(); +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/render_style.hpp b/src/mbgl/renderer/render_style.hpp new file mode 100644 index 0000000000..23a640c482 --- /dev/null +++ b/src/mbgl/renderer/render_style.hpp @@ -0,0 +1,92 @@ +#pragma once + +#include <mbgl/style/image.hpp> +#include <mbgl/renderer/render_source.hpp> +#include <mbgl/renderer/render_source_observer.hpp> +#include <mbgl/renderer/render_layer.hpp> +#include <mbgl/renderer/render_light.hpp> +#include <mbgl/text/glyph_manager_observer.hpp> +#include <mbgl/map/zoom_history.hpp> +#include <mbgl/map/mode.hpp> + +#include <memory> +#include <string> +#include <vector> + +namespace mbgl { + +class FileSource; +class GlyphManager; +class ImageManager; +class LineAtlas; +class RenderData; +class TransformState; +class RenderedQueryOptions; +class Scheduler; +class UpdateParameters; +class RenderStyleObserver; + +namespace style { +class Image; +class Source; +class Layer; +} // namespace style + +class RenderStyle : public GlyphManagerObserver, + public RenderSourceObserver { +public: + RenderStyle(Scheduler&, FileSource&); + ~RenderStyle() final; + + void setObserver(RenderStyleObserver*); + void update(const UpdateParameters&); + + bool isLoaded() const; + bool hasTransitions() const; + + RenderSource* getRenderSource(const std::string& id) const; + + std::vector<const RenderLayer*> getRenderLayers() const; + + RenderLayer* getRenderLayer(const std::string& id); + const RenderLayer* getRenderLayer(const std::string& id) const; + + const RenderLight& getRenderLight() const; + + RenderData getRenderData(MapDebugOptions, float angle); + + std::vector<Feature> queryRenderedFeatures(const ScreenLineString& geometry, + const TransformState& transformState, + const RenderedQueryOptions& options) const; + + void onLowMemory(); + + void dumpDebugLogs() const; + + Scheduler& scheduler; + FileSource& fileSource; + std::unique_ptr<GlyphManager> glyphManager; + std::unique_ptr<ImageManager> imageManager; + std::unique_ptr<LineAtlas> lineAtlas; + +private: + 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; + + // 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; + + RenderStyleObserver* observer; + ZoomHistory zoomHistory; +}; + +} // namespace mbgl diff --git a/src/mbgl/renderer/render_style_observer.hpp b/src/mbgl/renderer/render_style_observer.hpp new file mode 100644 index 0000000000..5852dd68b8 --- /dev/null +++ b/src/mbgl/renderer/render_style_observer.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include <exception> + +namespace mbgl { + +class RenderStyleObserver { +public: + virtual ~RenderStyleObserver() = default; + virtual void onInvalidate() {} + virtual void onResourceError(std::exception_ptr) {} +}; + +} // namespace mbgl diff --git a/src/mbgl/renderer/render_tile.cpp b/src/mbgl/renderer/render_tile.cpp index ce59186e61..59c3ea076b 100644 --- a/src/mbgl/renderer/render_tile.cpp +++ b/src/mbgl/renderer/render_tile.cpp @@ -1,5 +1,7 @@ #include <mbgl/renderer/render_tile.hpp> +#include <mbgl/renderer/painter.hpp> #include <mbgl/map/transform_state.hpp> +#include <mbgl/tile/tile.hpp> namespace mbgl { @@ -44,15 +46,15 @@ mat4 RenderTile::translatedClipMatrix(const std::array<float, 2>& translation, return translateVtxMatrix(nearClippedMatrix, translation, anchor, state); } -void RenderTile::calculateMatrices(const mat4& projMatrix, - const mat4& projClipMatrix, - const TransformState& transform) { +void RenderTile::startRender(Painter& painter) { + tile.upload(painter.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); + painter.state.matrixFor(matrix, id); + painter.state.matrixFor(nearClippedMatrix, id); + matrix::multiply(matrix, painter.projMatrix, matrix); + matrix::multiply(nearClippedMatrix, painter.nearClippedProjMatrix, nearClippedMatrix); } } // namespace mbgl diff --git a/src/mbgl/renderer/render_tile.hpp b/src/mbgl/renderer/render_tile.hpp index 02e8667eec..6677278873 100644 --- a/src/mbgl/renderer/render_tile.hpp +++ b/src/mbgl/renderer/render_tile.hpp @@ -11,6 +11,7 @@ namespace mbgl { class Tile; class TransformState; +class Painter; class RenderTile { public: @@ -35,9 +36,8 @@ public: style::TranslateAnchorType anchor, const TransformState&) const; - void calculateMatrices(const mat4& projMatrix, - const mat4& projClipMatrix, - const TransformState&); + void startRender(Painter&); + private: mat4 translateVtxMatrix(const mat4& tileMatrix, const std::array<float, 2>& translation, diff --git a/src/mbgl/renderer/sources/render_geojson_source.cpp b/src/mbgl/renderer/sources/render_geojson_source.cpp index 2b1eeea73b..2c6935b273 100644 --- a/src/mbgl/renderer/sources/render_geojson_source.cpp +++ b/src/mbgl/renderer/sources/render_geojson_source.cpp @@ -1,5 +1,6 @@ #include <mbgl/renderer/sources/render_geojson_source.hpp> #include <mbgl/renderer/render_tile.hpp> +#include <mbgl/renderer/painter.hpp> #include <mbgl/tile/geojson_tile.hpp> #include <mbgl/algorithm/generate_clip_ids.hpp> @@ -9,35 +10,29 @@ 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(); +const style::GeoJSONSource::Impl& RenderGeoJSONSource::impl() const { + return static_cast<const style::GeoJSONSource::Impl&>(*baseImpl); } -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); +bool RenderGeoJSONSource::isLoaded() const { + return tilePyramid.isLoaded(); } -void RenderGeoJSONSource::finishRender(Painter& painter) { - tilePyramid.finishRender(painter); -} +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_); -std::map<UnwrappedTileID, RenderTile>& RenderGeoJSONSource::getRenderTiles() { - return tilePyramid.getRenderTiles(); -} + enabled = needsRendering; -void RenderGeoJSONSource::updateTiles(const TileParameters& parameters) { - GeoJSONData* data_ = impl.getData(); + GeoJSONData* data_ = impl().getData(); if (!data_) { return; @@ -52,38 +47,43 @@ void RenderGeoJSONSource::updateTiles(const TileParameters& parameters) { } } - 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)); - }); + 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(Painter& painter) { + painter.clipIDGenerator.update(tilePyramid.getRenderTiles()); + tilePyramid.startRender(painter); +} + +void RenderGeoJSONSource::finishRender(Painter& painter) { + tilePyramid.finishRender(painter); } -void RenderGeoJSONSource::reloadTiles() { - tilePyramid.reloadTiles(); +std::map<UnwrappedTileID, 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 RenderStyle& style, + const RenderedQueryOptions& options) const { + return tilePyramid.queryRenderedFeatures(geometry, transformState, style, 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..b7c5a3fa7f 100644 --- a/src/mbgl/renderer/sources/render_geojson_source.hpp +++ b/src/mbgl/renderer/sources/render_geojson_source.hpp @@ -12,28 +12,17 @@ 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; - - // 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 startRender(Painter&) final; void finishRender(Painter&) final; std::map<UnwrappedTileID, RenderTile>& getRenderTiles() final; @@ -41,19 +30,25 @@ public: std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, + const RenderStyle& style, 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; }; +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..f5068b9d7f --- /dev/null +++ b/src/mbgl/renderer/sources/render_image_source.cpp @@ -0,0 +1,180 @@ +#include <mbgl/map/transform_state.hpp> +#include <mbgl/math/log2.hpp> +#include <mbgl/renderer/buckets/raster_bucket.hpp> +#include <mbgl/renderer/painter.hpp> +#include <mbgl/renderer/render_tile.hpp> +#include <mbgl/renderer/sources/render_image_source.hpp> +#include <mbgl/renderer/tile_parameters.hpp> +#include <mbgl/util/tile_coordinate.hpp> +#include <mbgl/util/tile_cover.hpp> + +namespace mbgl { + +using namespace style; + +RenderImageSource::RenderImageSource(Immutable<style::ImageSource::Impl> impl_) + : RenderSource(impl_), shouldRender(false) { +} + +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(Painter& painter) { + if (!isLoaded()) { + return; + } + + matrices.clear(); + + for (size_t i = 0; i < tileIds.size(); i++) { + mat4 matrix; + matrix::identity(matrix); + painter.state.matrixFor(matrix, tileIds[i]); + matrix::multiply(matrix, painter.projMatrix, matrix); + matrices.push_back(matrix); + } + + if (bucket->needsUpload() && shouldRender) { + bucket->upload(painter.context); + } +} + +void RenderImageSource::finishRender(Painter& painter) { + if (!isLoaded() || !shouldRender) { + return; + } + for (auto matrix : matrices) { + painter.renderTileDebug(matrix); + } +} + +std::unordered_map<std::string, std::vector<Feature>> +RenderImageSource::queryRenderedFeatures(const ScreenLineString&, + const TransformState&, + const RenderStyle&, + const RenderedQueryOptions&) const { + return {}; +} + +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) { + std::swap(baseImpl, baseImpl_); + + enabled = needsRendering; + + auto transformState = parameters.transformState; + auto size = transformState.getSize(); + double viewportHeight = size.height; + + auto coords = impl().getCoordinates(); + + // 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); + } + double width = nePixel.x - swPixel.x; + double height = nePixel.y - swPixel.y; + + // Don't bother drawing the ImageSource unless it occupies >4 screen pixels + shouldRender = (width * height > 4); + if (!shouldRender) { + return; + } + + // Calculate the optimum zoom level to determine the tile ids to use for transforms + double minScale = INFINITY; + if (width > 0 || height > 0) { + 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 = 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, ::floor(zoom)); + tileIds.clear(); + tileIds.push_back(tileCover[0]); + + // 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 }); + } + } + + // 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); + } + + const UnassociatedImage& image = impl().getImage(); + if (!image.valid()) { + return; + } + + if (!bucket || image != bucket->image) { + bucket = std::make_unique<RasterBucket>(image.clone()); + } else { + bucket->clear(); + } + + // 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 }, { 32767, 0 })); + bucket->vertices.emplace_back( + RasterProgram::layoutVertex({ geomCoords[3].x, geomCoords[3].y }, { 0, 32767 })); + bucket->vertices.emplace_back( + RasterProgram::layoutVertex({ geomCoords[2].x, geomCoords[2].y }, { 32767, 32767 })); + + bucket->indices.emplace_back(0, 1, 2); + bucket->indices.emplace_back(1, 2, 3); + + bucket->segments.emplace_back(0, 0, 4, 6); +} + +void RenderImageSource::render(Painter& painter, + PaintParameters& parameters, + const RenderLayer& layer) { + if (isLoaded() && !bucket->needsUpload() && shouldRender) { + for (auto matrix : matrices) { + bucket->render(painter, parameters, layer, matrix); + } + } +} + +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..88f1c56567 --- /dev/null +++ b/src/mbgl/renderer/sources/render_image_source.hpp @@ -0,0 +1,64 @@ +#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 RenderLayer; +class PaintParameters; +class RasterBucket; + +namespace gl { +class Context; +} // namespace gl + +class RenderImageSource : public RenderSource { +public: + RenderImageSource(Immutable<style::ImageSource::Impl>); + ~RenderImageSource() override; + + bool isLoaded() const final; + + void startRender(Painter&) final; + void render(Painter&, PaintParameters&, const RenderLayer&); + void finishRender(Painter&) final; + + void update(Immutable<style::Source::Impl>, + const std::vector<Immutable<style::Layer::Impl>>&, + bool needsRendering, + bool needsRelayout, + const TileParameters&) final; + + std::map<UnwrappedTileID, RenderTile>& getRenderTiles() final { + return tiles; + } + + std::unordered_map<std::string, std::vector<Feature>> + queryRenderedFeatures(const ScreenLineString& geometry, + const TransformState& transformState, + const RenderStyle& style, + const RenderedQueryOptions& options) const final; + + std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const final; + + void onLowMemory() final { + } + void dumpDebugLogs() const final; + +private: + const style::ImageSource::Impl& impl() const; + std::map<UnwrappedTileID, RenderTile> tiles; + + std::vector<UnwrappedTileID> tileIds; + std::unique_ptr<RasterBucket> bucket; + std::vector<mat4> matrices; + bool shouldRender; +}; + +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..20c148870e 100644 --- a/src/mbgl/renderer/sources/render_raster_source.cpp +++ b/src/mbgl/renderer/sources/render_raster_source.cpp @@ -6,34 +6,29 @@ 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); } +const style::RasterSource::Impl& RenderRasterSource::impl() const { + return static_cast<const style::RasterSource::Impl&>(*baseImpl); +} + bool RenderRasterSource::isLoaded() const { return tilePyramid.isLoaded(); } -void RenderRasterSource::invalidateTiles() { - tilePyramid.invalidateTiles(); -} +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_); -void RenderRasterSource::startRender(algorithm::ClipIDGenerator&, const mat4& projMatrix, const mat4& clipMatrix, const TransformState& transform) { - tilePyramid.startRender(projMatrix, clipMatrix, transform); -} + enabled = needsRendering; -void RenderRasterSource::finishRender(Painter& painter) { - tilePyramid.finishRender(painter); -} - -std::map<UnwrappedTileID, RenderTile>& RenderRasterSource::getRenderTiles() { - return tilePyramid.getRenderTiles(); -} - -void RenderRasterSource::updateTiles(const TileParameters& parameters) { - optional<Tileset> tileset = impl.getTileset(); + optional<Tileset> tileset = impl().getTileset(); if (!tileset) { return; @@ -41,29 +36,42 @@ 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::removeTiles() { - tilePyramid.removeTiles(); +void RenderRasterSource::startRender(Painter& painter) { + tilePyramid.startRender(painter); +} + +void RenderRasterSource::finishRender(Painter& painter) { + tilePyramid.finishRender(painter); } -void RenderRasterSource::reloadTiles() { - tilePyramid.reloadTiles(); +std::map<UnwrappedTileID, RenderTile>& RenderRasterSource::getRenderTiles() { + return tilePyramid.getRenderTiles(); } std::unordered_map<std::string, std::vector<Feature>> RenderRasterSource::queryRenderedFeatures(const ScreenLineString&, const TransformState&, + const RenderStyle&, const RenderedQueryOptions&) const { return {}; } @@ -72,10 +80,6 @@ std::vector<Feature> RenderRasterSource::querySourceFeatures(const SourceQueryOp 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..7d0c245e45 100644 --- a/src/mbgl/renderer/sources/render_raster_source.hpp +++ b/src/mbgl/renderer/sources/render_raster_source.hpp @@ -8,28 +8,17 @@ 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; - - // 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 startRender(Painter&) final; void finishRender(Painter&) final; std::map<UnwrappedTileID, RenderTile>& getRenderTiles() final; @@ -37,19 +26,25 @@ public: std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, + const RenderStyle& style, 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..4302fb21ee 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/painter.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); } +const style::VectorSource::Impl& RenderVectorSource::impl() const { + return static_cast<const style::VectorSource::Impl&>(*baseImpl); +} + bool RenderVectorSource::isLoaded() const { return tilePyramid.isLoaded(); } -void RenderVectorSource::invalidateTiles() { - tilePyramid.invalidateTiles(); -} +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::startRender(algorithm::ClipIDGenerator& generator, const mat4& projMatrix, const mat4& clipMatrix, const TransformState& transform) { - generator.update(tilePyramid.getRenderTiles()); - tilePyramid.startRender(projMatrix, clipMatrix, transform); -} + enabled = needsRendering; -void RenderVectorSource::finishRender(Painter& painter) { - tilePyramid.finishRender(painter); -} - -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(Painter& painter) { + painter.clipIDGenerator.update(tilePyramid.getRenderTiles()); + tilePyramid.startRender(painter); +} + +void RenderVectorSource::finishRender(Painter& painter) { + tilePyramid.finishRender(painter); } -void RenderVectorSource::reloadTiles() { - tilePyramid.reloadTiles(); +std::map<UnwrappedTileID, RenderTile>& RenderVectorSource::getRenderTiles() { + return tilePyramid.getRenderTiles(); } std::unordered_map<std::string, std::vector<Feature>> RenderVectorSource::queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, + const RenderStyle& style, const RenderedQueryOptions& options) const { - return tilePyramid.queryRenderedFeatures(geometry, transformState, options); + return tilePyramid.queryRenderedFeatures(geometry, transformState, style, 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..5e15fee533 100644 --- a/src/mbgl/renderer/sources/render_vector_source.hpp +++ b/src/mbgl/renderer/sources/render_vector_source.hpp @@ -8,28 +8,17 @@ 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; - - // 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 startRender(Painter&) final; void finishRender(Painter&) final; std::map<UnwrappedTileID, RenderTile>& getRenderTiles() final; @@ -37,19 +26,25 @@ public: std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, + const RenderStyle& style, 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_parameters.hpp b/src/mbgl/renderer/tile_parameters.hpp index 8f04baaec5..cf7a5b100a 100644 --- a/src/mbgl/renderer/tile_parameters.hpp +++ b/src/mbgl/renderer/tile_parameters.hpp @@ -8,30 +8,11 @@ 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 TransformState& transformState; @@ -39,9 +20,8 @@ public: FileSource& fileSource; const MapMode mode; AnnotationManager& annotationManager; - - // TODO: remove - style::Style& style; + ImageManager& imageManager; + GlyphManager& glyphManager; }; } // namespace mbgl diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp index 144afcb4f6..c2806299e3 100644 --- a/src/mbgl/renderer/tile_pyramid.cpp +++ b/src/mbgl/renderer/tile_pyramid.cpp @@ -39,18 +39,9 @@ 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) { +void TilePyramid::startRender(Painter& painter) { for (auto& pair : renderTiles) { - auto& tile = pair.second; - tile.calculateMatrices(projMatrix, clipMatrix, transform); + pair.second.startRender(painter); } } @@ -67,11 +58,34 @@ std::map<UnwrappedTileID, RenderTile>& TilePyramid::getRenderTiles() { return renderTiles; } -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; @@ -97,6 +111,9 @@ void TilePyramid::updateTiles(const TileParameters& parameters, auto retainTileFn = [&](Tile& tile, Resource::Necessity necessity) -> void { retain.emplace(tile.id); tile.setNecessity(necessity); + if (needsRelayout) { + tile.setLayers(layers); + } }; auto getTileFn = [&](const OverscaledTileID& tileID) -> Tile* { auto it = tiles.find(tileID); @@ -108,6 +125,7 @@ void TilePyramid::updateTiles(const TileParameters& parameters, tile = createTile(tileID); if (tile) { tile->setObserver(observer); + tile->setLayers(layers); } } if (!tile) { @@ -163,23 +181,9 @@ void TilePyramid::removeStaleTiles(const std::set<OverscaledTileID>& retain) { } } -void TilePyramid::removeTiles() { - renderTiles.clear(); - if (!tiles.empty()) { - removeStaleTiles({}); - } -} - -void TilePyramid::reloadTiles() { - cache.clear(); - - for (auto& pair : tiles) { - pair.second->redoLayout(); - } -} - std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, + const RenderStyle& style, const RenderedQueryOptions& options) const { std::unordered_map<std::string, std::vector<Feature>> result; if (renderTiles.empty() || geometry.empty()) { @@ -226,6 +230,7 @@ std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRendered renderTile.tile.queryRenderedFeatures(result, tileSpaceQueryGeometry, transformState, + style, options); } diff --git a/src/mbgl/renderer/tile_pyramid.hpp b/src/mbgl/renderer/tile_pyramid.hpp index b51c5342de..5846560808 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> @@ -20,6 +21,7 @@ namespace mbgl { class Painter; class TransformState; class RenderTile; +class RenderStyle; class RenderedQueryOptions; class SourceQueryOptions; class TileParameters; @@ -31,27 +33,16 @@ 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(); - - // 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 startRender(Painter&); void finishRender(Painter&); std::map<UnwrappedTileID, RenderTile>& getRenderTiles(); @@ -59,6 +50,7 @@ public: std::unordered_map<std::string, std::vector<Feature>> queryRenderedFeatures(const ScreenLineString& geometry, const TransformState& transformState, + const RenderStyle& style, const RenderedQueryOptions& options) const; std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const; 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..ce79a4f31b 100644 --- a/src/mbgl/renderer/update_parameters.hpp +++ b/src/mbgl/renderer/update_parameters.hpp @@ -1,11 +1,15 @@ #pragma once #include <mbgl/map/mode.hpp> -#include <mbgl/map/update.hpp> +#include <mbgl/map/transform_state.hpp> +#include <mbgl/util/chrono.hpp> +#include <mbgl/style/light.hpp> +#include <mbgl/style/image.hpp> +#include <mbgl/style/source.hpp> +#include <mbgl/style/layer.hpp> namespace mbgl { -class TransformState; class Scheduler; class FileSource; class AnnotationManager; @@ -13,11 +17,19 @@ class AnnotationManager; class UpdateParameters { public: const MapMode mode; - const Update updateFlags; const float pixelRatio; const MapDebugOptions debugOptions; const TimePoint timePoint; - const TransformState& transformState; + 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; + Scheduler& scheduler; FileSource& fileSource; AnnotationManager& annotationManager; |