Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

[core] Don't use a separate SpriteAtlas for annotation images #9003

Merged
merged 5 commits into from
May 26, 2017

Conversation

jfirebaugh
Copy link
Contributor

@jfirebaugh jfirebaugh commented May 15, 2017

Instead, just add them to the Style as needed. Includes changes from #8905 and takes care to avoid regressing #3817.

In order for this to not reduce the total combined capacity for spite and annotation images, while simultaneously not increasing the base memory consumption and failing the related test, it includes a switch to auto-growing the SpriteAtlas texture using shelf-pack-cpp. This also fixes #8247 ("Measured vectorFootprint = 31104204 Bytes").

@jfirebaugh jfirebaugh requested a review from kkaefer May 15, 2017 18:11
@jfirebaugh jfirebaugh force-pushed the render-sprite-atlas branch 2 times, most recently from d990b2c to 75fecf2 Compare May 15, 2017 21:16
@mb12
Copy link

mb12 commented May 16, 2017

@jfirebaugh The size/capacity of Style::spriteAtlas should also be changed to 2048x2048 since it now needs to have capacity for style sprite as well as user added annotations.

@@ -42,13 +42,8 @@ SpriteAtlas::SpriteAtlas(Size size_, float pixelRatio_)

SpriteAtlas::~SpriteAtlas() = default;

void SpriteAtlas::onSpriteLoaded(Images&& result) {
void SpriteAtlas::onSpriteLoaded() {
markAsLoaded();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can now remove this public method and set loaded = true directly.

if (style.getImage(image)) {
style.removeImage(image);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm worried about how this will interact with image names from the sprite sheet: Removing annotation images that have the same name as images in the sprite sheet means that they will be dangling.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went back and forth about this. We could prefix the ids when adding to the style. But using the same namespace would actually fix #4750.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use some sort of reference counting system?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you have in mind?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For glyphs, we store the GlyphRequestor in each Entry/GlyphValue, and only remove it from the atlas once all requestors are gone. We could use a similar model for requesting sprite images that were implicitly added to the sprite atlas.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I elected to use a prefix, as that solves both the removal issue and other issues with ID collisions.

@@ -167,13 +159,26 @@ void AnnotationManager::updateStyle(Style& style) {
shape.second->updateStyle(style);
}

for (const auto& image : images) {
if (!style.getImage(image.first)) {
style.addImage(image.first, std::make_unique<style::Image>(image.second));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move images instead of copying them? This will leave the Image object in the unordered_map empty, but we'll never access it again (there's no getImage method on the AnnotationManager). We can treat the mere presence of the key as the availability of this image, and only call style.addImage when we still own the image.

Copy link
Contributor Author

@jfirebaugh jfirebaugh May 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For clarity, I'd rather copy; it's cheap, because all that's being copied is an Immutable, which is a shared pointer. (Edit: we actually have to copy because annotation images must persist across style replacement.)

addSpriteImage(spriteImages, id, std::move(image), [&](style::Image& added) {
spriteAtlas.addImage(id, added.impl);
});
images.emplace(id, *image);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we making a copy here? We already own the style::Image object.

@jfirebaugh jfirebaugh force-pushed the render-sprite-atlas branch 2 times, most recently from 417d118 to 6c6cb2e Compare May 16, 2017 16:51
@jfirebaugh
Copy link
Contributor Author

In order for this to not reduce the total combined capacity for spite and annotation images, while simultaneously not increasing the base memory consumption and failing the related test, we'll need to implement auto-growing atlas textures.

if (entry.iconRect) {
bin.release(*entry.iconRect);
if (entry.iconBin) {
// shelfPack.release(*iconBin);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does shelfpack currently support removing bins?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not currently, we're waiting on v2 / mapbox/shelf-pack-cpp#5 which @bhousel is working on.

@jfirebaugh jfirebaugh changed the base branch from master to sprite-atlas-coordinates May 22, 2017 20:34
@jfirebaugh jfirebaugh changed the base branch from sprite-atlas-coordinates to master May 23, 2017 19:59
@jfirebaugh jfirebaugh force-pushed the render-sprite-atlas branch 7 times, most recently from 25018c1 to 5dc6a13 Compare May 26, 2017 04:30
@jfirebaugh
Copy link
Contributor Author

This is ready for re-review.

@jfirebaugh jfirebaugh force-pushed the render-sprite-atlas branch 2 times, most recently from e9cd79d to 4faedf6 Compare May 26, 2017 05:45
@@ -155,7 +148,7 @@ void AnnotationManager::updateStyle(Style& style) {
std::unique_ptr<SymbolLayer> layer = std::make_unique<SymbolLayer>(PointLayerID, SourceID);

layer->setSourceLayer(PointLayerID);
layer->setIconImage({"{sprite}"});
layer->setIconImage({SourceID + ".{sprite}"});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -166,13 +159,26 @@ void AnnotationManager::updateStyle(Style& style) {
shape.second->updateStyle(style);
}

for (const auto& image : images) {
if (!style.getImage(image.first)) {
style.addImage(std::make_unique<style::Image>(image.second));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we move them instead of copying them? What is the benefit of retaining the image?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry

// create a new image with the input ID prefixed by "com.mapbox.annotations".
std::string id = SourceID + "." + image->getID();
images.emplace(id,
style::Image(id, image->getImage().clone(), image->getPixelRatio(), image->isSdf()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a no-op when there is already an image with the same ID. Adding a different image with the same name will thus not have any affect. Is that the intended API behavior?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could have a list of IDs we currently have, a list of IDs to remove, and a map of new sprite images to add, then replace existing entries in the map when calling addImage.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point; I think the existing behavior is to replace the image (if it's the same size). I'll confirm and preserve that if so.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping a map of new sprite images to add isn't sufficient, because we also need to add all images in the case where there's a fresh style.

Eventually I think we should refactor AnnotationManager so that it updates the style immediately in each operation, and is notified when there's a fresh style, but that's a separate refactor. For now I made it add all images every updateStyle.

Instead, just add them to the Style as needed. Includes changes from #8905 and takes care to avoid regressing #3817.
@jfirebaugh jfirebaugh merged commit 2e0ceeb into master May 26, 2017
@kkaefer kkaefer deleted the render-sprite-atlas branch May 29, 2017 09:28
@kkaefer kkaefer added Core The cross-platform C++ core, aka mbgl refactor labels Jun 1, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Core The cross-platform C++ core, aka mbgl refactor
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Recover some headroom under the Memory.Footprint ceiling
4 participants