[core] Use a separate atlas and store for annotation sprites

Fixes #1488
This commit is contained in:
Adam Hunter
2015-11-16 16:26:02 -08:00
committed by John Firebaugh
parent 58886842bc
commit e1091db45e
14 changed files with 69 additions and 27 deletions

View File

@@ -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<const SpriteImage> 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;
}
}

View File

@@ -4,6 +4,8 @@
#include <mbgl/annotation/annotation.hpp>
#include <mbgl/annotation/point_annotation_impl.hpp>
#include <mbgl/annotation/shape_annotation_impl.hpp>
#include <mbgl/sprite/sprite_store.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/util/noncopyable.hpp>
@@ -21,7 +23,7 @@ class Style;
class AnnotationManager : private util::noncopyable {
public:
AnnotationManager();
AnnotationManager(float pixelRatio);
~AnnotationManager();
AnnotationIDs addPointAnnotations(const std::vector<PointAnnotation>&, const uint8_t maxZoom);
@@ -31,6 +33,10 @@ public:
AnnotationIDs getPointAnnotationsInBounds(const LatLngBounds&) const;
LatLngBounds getBoundsForAnnotations(const AnnotationIDs&) const;
void setSprite(const std::string& name, std::shared_ptr<const SpriteImage>);
double getTopOffsetPixelsForAnnotationSymbol(const std::string& name);
SpriteAtlas& getSpriteAtlas() { return spriteAtlas; }
void updateStyle(Style&);
void addTileMonitor(AnnotationTileMonitor&);
@@ -48,6 +54,9 @@ private:
ShapeAnnotationImpl::Map shapeAnnotations;
std::vector<std::string> obsoleteShapeAnnotationLayers;
std::set<AnnotationTileMonitor*> monitors;
SpriteStore spriteStore;
SpriteAtlas spriteAtlas;
};
}

View File

@@ -10,6 +10,7 @@ std::unique_ptr<StyleLayer> 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<Bucket> SymbolLayer::createBucket(StyleBucketParameters& paramet
// needed by this tile.
if (!parameters.partialParse) {
bucket->addFeatures(parameters.tileUID,
parameters.spriteAtlas,
*spriteAtlas,
parameters.glyphAtlas,
parameters.glyphStore,
parameters.collisionTile);

View File

@@ -7,6 +7,8 @@
namespace mbgl {
class SpriteAtlas;
class SymbolLayoutProperties {
public:
LayoutProperty<PlacementType> placement = PlacementType::Point;
@@ -94,6 +96,8 @@ public:
SymbolLayoutProperties layout;
SymbolPaintProperties paint;
SpriteAtlas* spriteAtlas;
};
}

View File

@@ -243,7 +243,7 @@ bool MapContext::renderSync(const TransformState& state, const FrameData& frame)
glObjectStore.performCleanup();
if (!painter) painter = std::make_unique<Painter>(data, transformState);
painter->render(*style, frame);
painter->render(*style, frame, data.getAnnotationManager()->getSpriteAtlas());
if (data.mode == MapMode::Still) {
callback(nullptr, std::move(view.readStillImage()));
@@ -269,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) {
@@ -299,14 +294,8 @@ void MapContext::onLowMemory() {
}
void MapContext::setSprite(const std::string& name, std::shared_ptr<const SpriteImage> 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() {

View File

@@ -24,6 +24,7 @@ public:
: mode(mode_)
, contextMode(contextMode_)
, pixelRatio(pixelRatio_)
, annotationManager(pixelRatio)
, animationTime(Duration::zero())
, defaultFadeDuration(mode_ == MapMode::Continuous ? std::chrono::milliseconds(300) : Duration::zero())
, defaultTransitionDuration(Duration::zero())

View File

@@ -64,7 +64,9 @@ TileParseResult TileWorker::parsePendingLayers() {
if (layer.type == StyleLayerType::Symbol) {
auto symbolBucket = dynamic_cast<SymbolBucket*>(bucket.get());
if (!symbolBucket->needsDependencies(*style.glyphStore, *style.spriteStore)) {
symbolBucket->addFeatures(reinterpret_cast<uintptr_t>(this), *style.spriteAtlas,
const SymbolLayer* symbolLayer = dynamic_cast<const SymbolLayer*>(&layer);
symbolBucket->addFeatures(reinterpret_cast<uintptr_t>(this),
*symbolLayer->spriteAtlas,
*style.glyphAtlas, *style.glyphStore, *collisionTile);
insertBucket(layer.bucketName(), std::move(bucket));
pending.erase(it++);

View File

@@ -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()) {

View File

@@ -93,7 +93,8 @@ public:
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);

View File

@@ -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 {

View File

@@ -24,9 +24,7 @@ SpriteAtlas::SpriteAtlas(dimension width_, dimension height_, float pixelRatio_,
pixelRatio(pixelRatio_),
store(store_),
bin(width_, height_),
data(std::make_unique<uint32_t[]>(pixelWidth * pixelHeight)),
dirty(true) {
std::fill(data.get(), data.get() + pixelWidth * pixelHeight, 0);
}
Rect<SpriteAtlas::dimension> 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<uint32_t[]>(pixelWidth * pixelHeight);
std::fill(data.get(), data.get() + pixelWidth * pixelHeight, 0);
}
const uint32_t *srcData = reinterpret_cast<const uint32_t *>(holder.texture->data.data());
if (!srcData) return;
const vec2<uint32_t> 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));

View File

@@ -66,6 +66,8 @@ public:
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 @@ private:
BinPack<dimension> bin;
std::map<Key, Holder> images;
std::set<std::string> uninitialized;
const std::unique_ptr<uint32_t[]> data;
std::unique_ptr<uint32_t[]> data;
std::atomic<bool> dirty;
bool fullUploadRequired = true;
GLuint texture = 0;

View File

@@ -2,6 +2,7 @@
#include <mbgl/map/map_data.hpp>
#include <mbgl/map/source.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/layer/symbol_layer.hpp>
#include <mbgl/sprite/sprite_store.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/style/style_layer.hpp>
@@ -88,6 +89,12 @@ StyleLayer* Style::getLayer(const std::string& id) const {
}
void Style::addLayer(util::ptr<StyleLayer> layer) {
if (SymbolLayer* symbolLayer = dynamic_cast<SymbolLayer*>(layer.get())) {
if (!symbolLayer->spriteAtlas) {
symbolLayer->spriteAtlas = spriteAtlas.get();
}
}
layers.emplace_back(std::move(layer));
}

View File

@@ -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]);