diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 8401976e150..bce99ebe4d5 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -178,8 +178,8 @@ class Map : private util::noncopyable { private: View& view; const std::unique_ptr transform; - const std::unique_ptr data; const std::unique_ptr> context; + MapData* data; enum class RenderState { never, diff --git a/include/mbgl/platform/default/glfw_view.hpp b/include/mbgl/platform/default/glfw_view.hpp index 2318cb6ccdd..a434b71bb1d 100644 --- a/include/mbgl/platform/default/glfw_view.hpp +++ b/include/mbgl/platform/default/glfw_view.hpp @@ -20,7 +20,6 @@ class GLFWView : public mbgl::View { std::array getFramebufferSize() const override; void initialize(mbgl::Map *map) override; - void notifyMapChange(mbgl::MapChange) override; void activate() override; void deactivate() override; void notify() override; @@ -62,7 +61,6 @@ class GLFWView : public mbgl::View { std::vector spriteIDs; private: - bool initializedDefaultMarker = false; bool fullscreen = false; const bool benchmark = false; bool tracking = false; diff --git a/platform/default/glfw_view.cpp b/platform/default/glfw_view.cpp index 48e9386fc7a..32fb9af6bb9 100644 --- a/platform/default/glfw_view.cpp +++ b/platform/default/glfw_view.cpp @@ -115,13 +115,7 @@ GLFWView::~GLFWView() { void GLFWView::initialize(mbgl::Map *map_) { View::initialize(map_); -} - -void GLFWView::notifyMapChange(mbgl::MapChange change) { - if (change == mbgl::MapChange::MapChangeDidFinishLoadingMap && !initializedDefaultMarker) { - initializedDefaultMarker = true; - map->setSprite("default_marker", makeSpriteImage(22, 22, 1)); - } + map->setSprite("default_marker", makeSpriteImage(22, 22, 1)); } void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action, int mods) { diff --git a/src/mbgl/annotation/annotation_manager.cpp b/src/mbgl/annotation/annotation_manager.cpp index 5b1138a14af..83cf34ac66a 100644 --- a/src/mbgl/annotation/annotation_manager.cpp +++ b/src/mbgl/annotation/annotation_manager.cpp @@ -10,7 +10,11 @@ namespace mbgl { const std::string AnnotationManager::SourceID = "com.mapbox.annotations"; const std::string AnnotationManager::PointLayerID = "com.mapbox.annotations.points"; -AnnotationManager::AnnotationManager() = default; +AnnotationManager::AnnotationManager(float pixelRatio) + : spriteStore(pixelRatio), + spriteAtlas(512, 512, pixelRatio, spriteStore) { +} + AnnotationManager::~AnnotationManager() = default; AnnotationIDs @@ -122,6 +126,7 @@ void AnnotationManager::updateStyle(Style& style) { layer->sourceLayer = PointLayerID; layer->layout.icon.image = std::string("{sprite}"); layer->layout.icon.allowOverlap = true; + layer->spriteAtlas = &spriteAtlas; style.addLayer(std::move(layer)); } @@ -152,4 +157,14 @@ void AnnotationManager::removeTileMonitor(AnnotationTileMonitor& monitor) { monitors.erase(&monitor); } +void AnnotationManager::setSprite(const std::string& name, std::shared_ptr sprite) { + spriteStore.setSprite(name, sprite); + spriteAtlas.updateDirty(); +} + +double AnnotationManager::getTopOffsetPixelsForAnnotationSymbol(const std::string& name) { + auto sprite = spriteStore.getSprite(name); + return sprite ? -sprite->height / 2 : 0; +} + } diff --git a/src/mbgl/annotation/annotation_manager.hpp b/src/mbgl/annotation/annotation_manager.hpp index f1b41c9ccce..9fbbcc57c83 100644 --- a/src/mbgl/annotation/annotation_manager.hpp +++ b/src/mbgl/annotation/annotation_manager.hpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include @@ -21,7 +23,7 @@ class Style; class AnnotationManager : private util::noncopyable { public: - AnnotationManager(); + AnnotationManager(float pixelRatio); ~AnnotationManager(); AnnotationIDs addPointAnnotations(const std::vector&, const uint8_t maxZoom); @@ -31,6 +33,10 @@ class AnnotationManager : private util::noncopyable { AnnotationIDs getPointAnnotationsInBounds(const LatLngBounds&) const; LatLngBounds getBoundsForAnnotations(const AnnotationIDs&) const; + void setSprite(const std::string& name, std::shared_ptr); + double getTopOffsetPixelsForAnnotationSymbol(const std::string& name); + SpriteAtlas& getSpriteAtlas() { return spriteAtlas; } + void updateStyle(Style&); void addTileMonitor(AnnotationTileMonitor&); @@ -48,6 +54,9 @@ class AnnotationManager : private util::noncopyable { ShapeAnnotationImpl::Map shapeAnnotations; std::vector obsoleteShapeAnnotationLayers; std::set monitors; + + SpriteStore spriteStore; + SpriteAtlas spriteAtlas; }; } diff --git a/src/mbgl/layer/symbol_layer.cpp b/src/mbgl/layer/symbol_layer.cpp index 8e43d3454e2..f9549996147 100644 --- a/src/mbgl/layer/symbol_layer.cpp +++ b/src/mbgl/layer/symbol_layer.cpp @@ -10,6 +10,7 @@ std::unique_ptr SymbolLayer::clone() const { result->copy(*this); result->layout = layout; result->paint = paint; + result->spriteAtlas = spriteAtlas; return std::move(result); } @@ -178,7 +179,7 @@ std::unique_ptr SymbolLayer::createBucket(StyleBucketParameters& paramet // needed by this tile. if (!parameters.partialParse) { bucket->addFeatures(parameters.tileUID, - parameters.spriteAtlas, + *spriteAtlas, parameters.glyphAtlas, parameters.glyphStore, parameters.collisionTile); diff --git a/src/mbgl/layer/symbol_layer.hpp b/src/mbgl/layer/symbol_layer.hpp index 9e4555350a2..1a9e4587bb5 100644 --- a/src/mbgl/layer/symbol_layer.hpp +++ b/src/mbgl/layer/symbol_layer.hpp @@ -7,6 +7,8 @@ namespace mbgl { +class SpriteAtlas; + class SymbolLayoutProperties { public: LayoutProperty placement = PlacementType::Point; @@ -94,6 +96,8 @@ class SymbolLayer : public StyleLayer { SymbolLayoutProperties layout; SymbolPaintProperties paint; + + SpriteAtlas* spriteAtlas; }; } diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 57f8c3e7f30..08265ae1e89 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -17,8 +17,10 @@ namespace mbgl { Map::Map(View& view_, FileSource& fileSource, MapMode mapMode, GLContextMode contextMode, ConstrainMode constrainMode) : view(view_), transform(std::make_unique(view, constrainMode)), - data(std::make_unique(mapMode, contextMode, view.getPixelRatio())), - context(std::make_unique>(util::ThreadContext{"Map", util::ThreadType::Map, util::ThreadPriority::Regular}, view, fileSource, *data)) + context(std::make_unique>( + util::ThreadContext{"Map", util::ThreadType::Map, util::ThreadPriority::Regular}, + view, fileSource, mapMode, contextMode, view.getPixelRatio())), + data(&context->invokeSync(&MapContext::getData)) { view.initialize(this); update(Update::Dimensions); diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index 400b2880daf..17d91ab8616 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -25,9 +25,10 @@ namespace mbgl { -MapContext::MapContext(View& view_, FileSource& fileSource, MapData& data_) +MapContext::MapContext(View& view_, FileSource& fileSource, MapMode mode_, GLContextMode contextMode_, const float pixelRatio_) : view(view_), - data(data_), + dataPtr(std::make_unique(mode_, contextMode_, pixelRatio_)), + data(*dataPtr), asyncUpdate([this] { update(); }), asyncInvalidate([&view_] { view_.invalidate(); }), texturePool(std::make_unique()) { @@ -57,6 +58,7 @@ void MapContext::cleanup() { style.reset(); painter.reset(); texturePool.reset(); + dataPtr.reset(); glObjectStore.performCleanup(); @@ -241,7 +243,7 @@ bool MapContext::renderSync(const TransformState& state, const FrameData& frame) glObjectStore.performCleanup(); if (!painter) painter = std::make_unique(data, transformState); - painter->render(*style, frame); + painter->render(*style, frame, data.getAnnotationManager()->getSpriteAtlas()); if (data.mode == MapMode::Still) { callback(nullptr, std::move(view.readStillImage())); @@ -267,12 +269,7 @@ bool MapContext::isLoaded() const { double MapContext::getTopOffsetPixelsForAnnotationSymbol(const std::string& symbol) { assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); - auto sprite = style->spriteStore->getSprite(symbol); - if (sprite) { - return -sprite->height / 2; - } else { - return 0; - } + return data.getAnnotationManager()->getTopOffsetPixelsForAnnotationSymbol(symbol); } void MapContext::setSourceTileCacheSize(size_t size) { @@ -297,14 +294,8 @@ void MapContext::onLowMemory() { } void MapContext::setSprite(const std::string& name, std::shared_ptr sprite) { - if (!style) { - Log::Info(Event::Sprite, "Ignoring sprite without stylesheet"); - return; - } - - style->spriteStore->setSprite(name, sprite); - - style->spriteAtlas->updateDirty(); + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); + data.getAnnotationManager()->setSprite(name, sprite); } void MapContext::onTileDataChanged() { diff --git a/src/mbgl/map/map_context.hpp b/src/mbgl/map/map_context.hpp index c0ee68a6146..06be31ed85e 100644 --- a/src/mbgl/map/map_context.hpp +++ b/src/mbgl/map/map_context.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -27,9 +28,11 @@ struct FrameData { class MapContext : public Style::Observer { public: - MapContext(View&, FileSource&, MapData&); + MapContext(View&, FileSource&, MapMode, GLContextMode, const float pixelRatio); ~MapContext(); + MapData& getData() { return data; } + void pause(); void triggerUpdate(const TransformState&, Update = Update::Nothing); @@ -69,6 +72,7 @@ class MapContext : public Style::Observer { void loadStyleJSON(const std::string& json, const std::string& base); View& view; + std::unique_ptr dataPtr; MapData& data; util::GLObjectStore glObjectStore; diff --git a/src/mbgl/map/map_data.hpp b/src/mbgl/map/map_data.hpp index 43765e25b2d..cf6ad20475c 100644 --- a/src/mbgl/map/map_data.hpp +++ b/src/mbgl/map/map_data.hpp @@ -24,6 +24,7 @@ class MapData { : mode(mode_) , contextMode(contextMode_) , pixelRatio(pixelRatio_) + , annotationManager(pixelRatio) , animationTime(Duration::zero()) , defaultFadeDuration(mode_ == MapMode::Continuous ? std::chrono::milliseconds(300) : Duration::zero()) , defaultTransitionDuration(Duration::zero()) diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 9dc0698db7c..9686d579ae8 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -64,7 +64,9 @@ TileParseResult TileWorker::parsePendingLayers() { if (layer.type == StyleLayerType::Symbol) { auto symbolBucket = dynamic_cast(bucket.get()); if (!symbolBucket->needsDependencies(*style.glyphStore, *style.spriteStore)) { - symbolBucket->addFeatures(reinterpret_cast(this), *style.spriteAtlas, + const SymbolLayer* symbolLayer = dynamic_cast(&layer); + symbolBucket->addFeatures(reinterpret_cast(this), + *symbolLayer->spriteAtlas, *style.glyphAtlas, *style.glyphStore, *collisionTile); insertBucket(layer.bucketName(), std::move(bucket)); pending.erase(it++); diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index a3902fece06..9c64fc9f905 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -128,7 +128,7 @@ void Painter::prepareTile(const Tile& tile) { config.stencilFunc = { GL_EQUAL, ref, mask }; } -void Painter::render(const Style& style, const FrameData& frame_) { +void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& annotationSpriteAtlas) { frame = frame_; glyphAtlas = style.glyphAtlas.get(); @@ -158,6 +158,7 @@ void Painter::render(const Style& style, const FrameData& frame_) { spriteAtlas->upload(); lineAtlas->upload(); glyphAtlas->upload(); + annotationSpriteAtlas.upload(); for (const auto& item : order) { if (item.bucket && item.bucket->needsUpload()) { diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp index 5de1031d23c..0995ee4e440 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -93,7 +93,8 @@ class Painter : private util::noncopyable { void changeMatrix(); void render(const Style& style, - const FrameData& frame); + const FrameData& frame, + SpriteAtlas& annotationSpriteAtlas); // Renders debug information for a tile. void renderTileDebug(const Tile& tile); diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp index f46a9c84543..4a00d941db4 100644 --- a/src/mbgl/renderer/painter_symbol.cpp +++ b/src/mbgl/renderer/painter_symbol.cpp @@ -192,7 +192,8 @@ void Painter::renderSymbol(SymbolBucket& bucket, const SymbolLayer& layer, const const float fontSize = properties.icon.size; const float fontScale = fontSize / 1.0f; - spriteAtlas->bind(state.isChanging() || layout.placement == PlacementType::Line + SpriteAtlas* activeSpriteAtlas = layer.spriteAtlas; + activeSpriteAtlas->bind(state.isChanging() || layout.placement == PlacementType::Line || angleOffset != 0 || fontScale != 1 || sdf || state.getPitch() != 0); if (sdf) { @@ -202,7 +203,7 @@ void Painter::renderSymbol(SymbolBucket& bucket, const SymbolLayer& layer, const layout.icon, properties.icon, 1.0f, - {{ float(spriteAtlas->getWidth()) / 4.0f, float(spriteAtlas->getHeight()) / 4.0f }}, + {{ float(activeSpriteAtlas->getWidth()) / 4.0f, float(activeSpriteAtlas->getHeight()) / 4.0f }}, *sdfIconShader, &SymbolBucket::drawIcons); } else { diff --git a/src/mbgl/sprite/sprite_atlas.cpp b/src/mbgl/sprite/sprite_atlas.cpp index 45b0511c68c..ae71f18f037 100644 --- a/src/mbgl/sprite/sprite_atlas.cpp +++ b/src/mbgl/sprite/sprite_atlas.cpp @@ -24,9 +24,7 @@ SpriteAtlas::SpriteAtlas(dimension width_, dimension height_, float pixelRatio_, pixelRatio(pixelRatio_), store(store_), bin(width_, height_), - data(std::make_unique(pixelWidth * pixelHeight)), dirty(true) { - std::fill(data.get(), data.get() + pixelWidth * pixelHeight, 0); } Rect SpriteAtlas::allocateImage(const size_t pixel_width, const size_t pixel_height) { @@ -103,6 +101,11 @@ SpriteAtlasPosition SpriteAtlas::getPosition(const std::string& name, bool repea } void SpriteAtlas::copy(const Holder& holder, const bool wrap) { + if (!data) { + data = std::make_unique(pixelWidth * pixelHeight); + std::fill(data.get(), data.get() + pixelWidth * pixelHeight, 0); + } + const uint32_t *srcData = reinterpret_cast(holder.texture->data.data()); if (!srcData) return; const vec2 srcSize { holder.texture->pixelWidth, holder.texture->pixelHeight }; @@ -189,6 +192,10 @@ void SpriteAtlas::updateDirty() { } void SpriteAtlas::bind(bool linear) { + if (!data) { + return; // Empty atlas + } + if (!texture) { MBGL_CHECK_ERROR(glGenTextures(1, &texture)); MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture)); diff --git a/src/mbgl/sprite/sprite_atlas.hpp b/src/mbgl/sprite/sprite_atlas.hpp index 0d86279e2d4..0e3e8cf225d 100644 --- a/src/mbgl/sprite/sprite_atlas.hpp +++ b/src/mbgl/sprite/sprite_atlas.hpp @@ -66,6 +66,8 @@ class SpriteAtlas : public util::noncopyable { inline dimension getTextureWidth() const { return pixelWidth; } inline dimension getTextureHeight() const { return pixelHeight; } inline float getPixelRatio() const { return pixelRatio; } + + // Only for use in tests. inline const uint32_t* getData() const { return data.get(); } private: @@ -90,7 +92,7 @@ class SpriteAtlas : public util::noncopyable { BinPack bin; std::map images; std::set uninitialized; - const std::unique_ptr data; + std::unique_ptr data; std::atomic dirty; bool fullUploadRequired = true; GLuint texture = 0; diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index 69f28e86bb2..aa514de40cd 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -88,6 +89,12 @@ StyleLayer* Style::getLayer(const std::string& id) const { } void Style::addLayer(util::ptr layer) { + if (SymbolLayer* symbolLayer = dynamic_cast(layer.get())) { + if (!symbolLayer->spriteAtlas) { + symbolLayer->spriteAtlas = spriteAtlas.get(); + } + } + layers.emplace_back(std::move(layer)); } diff --git a/test/miscellaneous/map_context.cpp b/test/miscellaneous/map_context.cpp index fac21ee9597..9645572358c 100644 --- a/test/miscellaneous/map_context.cpp +++ b/test/miscellaneous/map_context.cpp @@ -13,9 +13,9 @@ TEST(MapContext, DoubleStyleLoad) { std::shared_ptr display = std::make_shared(); HeadlessView view(display, 1, 512, 512); DefaultFileSource fileSource(nullptr); - MapData data(MapMode::Continuous, GLContextMode::Unique, view.getPixelRatio()); - util::Thread context({"Map", util::ThreadType::Map, util::ThreadPriority::Regular}, view, fileSource, data); + util::Thread context({"Map", util::ThreadType::Map, util::ThreadPriority::Regular}, + view, fileSource, MapMode::Continuous, GLContextMode::Unique, view.getPixelRatio()); context.invokeSync(&MapContext::setStyleJSON, "", ""); context.invokeSync(&MapContext::setStyleJSON, "", ""); diff --git a/test/sprite/sprite_atlas.cpp b/test/sprite/sprite_atlas.cpp index e54a88dabe2..ddbd54406d7 100644 --- a/test/sprite/sprite_atlas.cpp +++ b/test/sprite/sprite_atlas.cpp @@ -27,7 +27,7 @@ TEST(Sprite, SpriteAtlas) { EXPECT_EQ(112, atlas.getTextureHeight()); // Image hasn't been created yet. - EXPECT_TRUE(atlas.getData()); + EXPECT_FALSE(atlas.getData()); auto metro = atlas.getImage("metro", false); EXPECT_EQ(0, metro.pos.x); @@ -42,6 +42,8 @@ TEST(Sprite, SpriteAtlas) { EXPECT_EQ(18, metro.texture->pixelHeight); EXPECT_EQ(1.0f, metro.texture->pixelRatio); + EXPECT_TRUE(atlas.getData()); + auto pos = atlas.getPosition("metro", false); EXPECT_DOUBLE_EQ(20, pos.size[0]); EXPECT_DOUBLE_EQ(20, pos.size[1]);