Hold internal reference to Sprite in SpriteAtlas

This commit is contained in:
John Firebaugh
2014-10-22 14:25:10 -07:00
parent 14829db508
commit 4f7bc80664
6 changed files with 40 additions and 51 deletions

View File

@@ -3,6 +3,7 @@
#include <mbgl/geometry/binpack.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/ptr.hpp>
#include <string>
#include <map>
@@ -26,7 +27,6 @@ class SpriteAtlas : public util::noncopyable {
public:
typedef uint16_t dimension;
public:
// Add way to construct this from another SpriteAtlas (e.g. with another pixelRatio)
SpriteAtlas(dimension width, dimension height);
~SpriteAtlas();
@@ -34,22 +34,16 @@ public:
// Changes the pixel ratio.
bool resize(float newRatio);
// Update uninitialized (= outdated) sprites in this atlas from the given sprite.
void update(const Sprite &sprite);
// Changes the source sprite.
void setSprite(util::ptr<Sprite> sprite);
// Returns the coordinates of an image that is sourced from the sprite image.
// This getter attempts to read the image from the sprite if it is already loaded.
// In that case, it copies it into the sprite atlas and returns the dimensions.
// Otherwise, it returns a 0/0/0/0 rect.
Rect<dimension> getImage(const std::string &name, const Sprite &sprite);
Rect<dimension> getImage(const std::string& name);
// Returns the coordinates of an image that is sourced from the sprite image.
// This getter waits until the sprite image was loaded, copies it into the sprite
// image and returns the dimensions.
// NEVER CALL THIS FUNCTION FROM THE RENDER THREAD! it is blocking.
Rect<dimension> waitForImage(const std::string &name, const Sprite &sprite);
SpriteAtlasPosition getPosition(const std::string &name, const Sprite &sprite, bool repeating = false);
SpriteAtlasPosition getPosition(const std::string& name, bool repeating = false);
// Binds the image buffer of this sprite atlas to the GPU, and uploads data if it is out
// of date.
@@ -61,19 +55,18 @@ public:
inline float getTextureHeight() const { return height * pixelRatio; }
inline float getPixelRatio() const { return pixelRatio; }
private:
void allocate();
Rect<SpriteAtlas::dimension> allocateImage(size_t width, size_t height);
void copy(const Rect<dimension> &dst, const SpritePosition &src, const Sprite &sprite);
public:
const dimension width = 0;
const dimension height = 0;
private:
std::mutex mtx;
void allocate();
Rect<SpriteAtlas::dimension> allocateImage(size_t width, size_t height);
void copy(const Rect<dimension>& dst, const SpritePosition& src);
std::recursive_mutex mtx;
float pixelRatio = 1.0f;
BinPack<dimension> bin;
util::ptr<Sprite> sprite;
std::map<std::string, Rect<dimension>> images;
std::set<std::string> uninitialized;
uint32_t *data = nullptr;

View File

@@ -24,7 +24,7 @@ SpriteAtlas::SpriteAtlas(dimension width_, dimension height_)
bool SpriteAtlas::resize(const float newRatio) {
if (pixelRatio == newRatio) return false;
std::lock_guard<std::mutex> lock(mtx);
std::lock_guard<std::recursive_mutex> lock(mtx);
const float oldRatio = pixelRatio;
pixelRatio = newRatio;
@@ -104,15 +104,15 @@ Rect<SpriteAtlas::dimension> SpriteAtlas::allocateImage(size_t pixel_width, size
return rect;
}
Rect<SpriteAtlas::dimension> SpriteAtlas::getImage(const std::string &name, const Sprite &sprite) {
std::lock_guard<std::mutex> lock(mtx);
Rect<SpriteAtlas::dimension> SpriteAtlas::getImage(const std::string& name) {
std::lock_guard<std::recursive_mutex> lock(mtx);
auto rect_it = images.find(name);
if (rect_it != images.end()) {
return rect_it->second;
}
const SpritePosition &pos = sprite.getSpritePosition(name);
const SpritePosition &pos = sprite->getSpritePosition(name);
if (!pos.width || !pos.height) {
return Rect<dimension> { 0, 0, 0, 0 };
}
@@ -127,16 +127,17 @@ Rect<SpriteAtlas::dimension> SpriteAtlas::getImage(const std::string &name, cons
images.emplace(name, rect);
copy(rect, pos, sprite);
copy(rect, pos);
return rect;
}
SpriteAtlasPosition SpriteAtlas::getPosition(const std::string& name, const Sprite& sprite, bool repeating) {
SpriteAtlasPosition SpriteAtlas::getPosition(const std::string& name, bool repeating) {
std::lock_guard<std::recursive_mutex> lock(mtx);
// `repeating` indicates that the image will be used in a repeating pattern
// repeating pattern images are assumed to have a 1px padding that mirrors the opposite edge
// positions for repeating images are adjusted to exclude the edge
Rect<dimension> rect = getImage(name, sprite);
Rect<dimension> rect = getImage(name);
const int r = repeating ? 1 : 0;
return SpriteAtlasPosition {
{{ float(rect.w) / pixelRatio, float(rect.h) / pixelRatio }},
@@ -145,11 +146,6 @@ SpriteAtlasPosition SpriteAtlas::getPosition(const std::string& name, const Spri
};
}
Rect<SpriteAtlas::dimension> SpriteAtlas::waitForImage(const std::string &name, const Sprite &sprite) {
sprite.waitUntilLoaded();
return getImage(name, sprite);
}
void SpriteAtlas::allocate() {
if (!data) {
dimension w = static_cast<dimension>(width * pixelRatio);
@@ -159,15 +155,15 @@ void SpriteAtlas::allocate() {
}
}
void SpriteAtlas::copy(const Rect<dimension> &dst, const SpritePosition &src, const Sprite &sprite) {
if (!sprite.raster) return;
const uint32_t *src_img = reinterpret_cast<const uint32_t *>(sprite.raster->getData());
void SpriteAtlas::copy(const Rect<dimension>& dst, const SpritePosition& src) {
if (!sprite->raster) return;
const uint32_t *src_img = reinterpret_cast<const uint32_t *>(sprite->raster->getData());
allocate();
uint32_t *dst_img = reinterpret_cast<uint32_t *>(data);
copy_bitmap(
/* source buffer */ src_img,
/* source stride */ sprite.raster->getWidth(),
/* source stride */ sprite->raster->getWidth(),
/* source x */ src.x,
/* source y */ src.y,
/* dest buffer */ dst_img,
@@ -181,14 +177,16 @@ void SpriteAtlas::copy(const Rect<dimension> &dst, const SpritePosition &src, co
dirty = true;
}
void SpriteAtlas::setSprite(util::ptr<Sprite> sprite_) {
std::lock_guard<std::recursive_mutex> lock(mtx);
void SpriteAtlas::update(const Sprite &sprite) {
if (!sprite.isLoaded()) return;
sprite = sprite_;
SpriteAtlas &atlas = *this;
util::erase_if(uninitialized, [&sprite, &atlas](const std::string &name) {
Rect<dimension> dst = atlas.getImage(name, sprite);
const SpritePosition &src = sprite.getSpritePosition(name);
if (!sprite->isLoaded()) return;
util::erase_if(uninitialized, [this](const std::string &name) {
Rect<dimension> dst = getImage(name);
const SpritePosition& src = sprite->getSpritePosition(name);
if (!src) {
if (debug::spriteWarnings) {
fprintf(stderr, "[WARNING] sprite doesn't have image with name '%s'\n", name.c_str());
@@ -196,8 +194,8 @@ void SpriteAtlas::update(const Sprite &sprite) {
return true;
}
if (src.width == dst.w * atlas.pixelRatio && src.height == dst.h * atlas.pixelRatio && src.pixelRatio == atlas.pixelRatio) {
atlas.copy(dst, src, sprite);
if (src.width == dst.w * pixelRatio && src.height == dst.h * pixelRatio && src.pixelRatio == pixelRatio) {
copy(dst, src);
return true;
} else {
if (debug::spriteWarnings) {
@@ -228,7 +226,7 @@ void SpriteAtlas::bind(bool linear) {
}
if (dirty) {
std::lock_guard<std::mutex> lock(mtx);
std::lock_guard<std::recursive_mutex> lock(mtx);
allocate();
if (first) {
@@ -257,15 +255,12 @@ void SpriteAtlas::bind(bool linear) {
);
}
#if defined(DEBUG)
// platform::show_color_debug_image("Sprite Atlas", reinterpret_cast<char *>(data), width, height, width * pixelRatio, height * pixelRatio);
#endif
dirty = false;
}
};
SpriteAtlas::~SpriteAtlas() {
std::lock_guard<std::mutex> lock(mtx);
std::lock_guard<std::recursive_mutex> lock(mtx);
glDeleteTextures(1, &texture);
texture = 0;

View File

@@ -646,7 +646,7 @@ void Map::prepare() {
// Allow the sprite atlas to potentially pull new sprite images if needed.
spriteAtlas->resize(state.getPixelRatio());
spriteAtlas->update(*getSprite());
spriteAtlas->setSprite(getSprite());
updateTiles();
}

View File

@@ -218,7 +218,7 @@ void Painter::renderBackground(util::ptr<StyleLayer> layer_desc) {
return;
SpriteAtlas &spriteAtlas = *map.getSpriteAtlas();
SpriteAtlasPosition imagePos = spriteAtlas.getPosition(properties.image, *sprite, true);
SpriteAtlasPosition imagePos = spriteAtlas.getPosition(properties.image, true);
float zoomFraction = map.getState().getZoomFraction();
useProgram(patternShader->program);

View File

@@ -61,7 +61,7 @@ void Painter::renderFill(FillBucket& bucket, util::ptr<StyleLayer> layer_desc, c
Sprite &sprite = *map.getSprite();
if (pass == RenderPass::Translucent && sprite) {
SpriteAtlas &spriteAtlas = *map.getSpriteAtlas();
const SpriteAtlasPosition pos = spriteAtlas.getPosition(properties.image, sprite, true);
const SpriteAtlasPosition pos = spriteAtlas.getPosition(properties.image, true);
const float mix = std::fmod(float(map.getState().getZoom()), 1.0f);
const float factor = 8.0 / std::pow(2, map.getState().getIntegerZoom() - id.z);

View File

@@ -148,7 +148,8 @@ void SymbolBucket::addFeatures(const VectorTileLayer &layer, const FilterExpress
// if feature has icon, get sprite atlas position
if (feature.sprite.length()) {
image = spriteAtlas.waitForImage(feature.sprite, sprite);
sprite.waitUntilLoaded();
image = spriteAtlas.getImage(feature.sprite);
if (sprite.getSpritePosition(feature.sprite).sdf) {
sdfIcons = true;