summaryrefslogtreecommitdiff
path: root/src/mbgl/sprite
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2016-10-26 16:39:25 -0700
committerKonstantin Käfer <mail@kkaefer.com>2016-11-01 18:41:52 +0100
commit9e3839781fdf1b1c6a2d61a5de9b2c7ddd68e9ed (patch)
treecde9eb4e99341e5200ca5a06a4a1d0fc602c9232 /src/mbgl/sprite
parente2981c890e9a758c4dee703fa9e25e5d9eff65ce (diff)
downloadqtlocation-mapboxgl-9e3839781fdf1b1c6a2d61a5de9b2c7ddd68e9ed.tar.gz
[core] convert SpriteAtlas to use managed texture handling
Diffstat (limited to 'src/mbgl/sprite')
-rw-r--r--src/mbgl/sprite/sprite_atlas.cpp126
-rw-r--r--src/mbgl/sprite/sprite_atlas.hpp33
2 files changed, 50 insertions, 109 deletions
diff --git a/src/mbgl/sprite/sprite_atlas.cpp b/src/mbgl/sprite/sprite_atlas.cpp
index f8417c3372..24563ff43d 100644
--- a/src/mbgl/sprite/sprite_atlas.cpp
+++ b/src/mbgl/sprite/sprite_atlas.cpp
@@ -1,7 +1,6 @@
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/sprite/sprite_atlas_observer.hpp>
#include <mbgl/sprite/sprite_parser.hpp>
-#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/context.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/platform/platform.hpp>
@@ -28,15 +27,12 @@ struct SpriteAtlas::Loader {
std::unique_ptr<AsyncRequest> spriteRequest;
};
-SpriteAtlas::SpriteAtlas(dimension width_, dimension height_, float pixelRatio_)
- : width(width_),
- height(height_),
- pixelWidth(std::ceil(width * pixelRatio_)),
- pixelHeight(std::ceil(height * pixelRatio_)),
+SpriteAtlas::SpriteAtlas(Size size_, float pixelRatio_)
+ : size(std::move(size_)),
pixelRatio(pixelRatio_),
observer(&nullObserver),
- bin(width_, height_),
- dirtyFlag(true) {
+ bin(size.width, size.height),
+ dirty(true) {
}
SpriteAtlas::~SpriteAtlas() = default;
@@ -162,7 +158,7 @@ std::shared_ptr<const SpriteImage> SpriteAtlas::getSprite(const std::string& nam
}
}
-Rect<SpriteAtlas::dimension> SpriteAtlas::allocateImage(const SpriteImage& spriteImage) {
+Rect<uint16_t> SpriteAtlas::allocateImage(const SpriteImage& spriteImage) {
const uint16_t pixel_width = std::ceil(spriteImage.image.size.width / pixelRatio);
const uint16_t pixel_height = std::ceil(spriteImage.image.size.height / pixelRatio);
@@ -175,7 +171,7 @@ Rect<SpriteAtlas::dimension> SpriteAtlas::allocateImage(const SpriteImage& sprit
// We have to allocate a new area in the bin, and store an empty image in it.
// Add a 1px border around every image.
- Rect<dimension> rect = bin.allocate(pack_width, pack_height);
+ Rect<uint16_t> rect = bin.allocate(pack_width, pack_height);
if (rect.w == 0) {
return rect;
}
@@ -197,7 +193,7 @@ optional<SpriteAtlasElement> SpriteAtlas::getImage(const std::string& name,
return {};
}
- Rect<dimension> rect = allocateImage(*sprite);
+ Rect<uint16_t> rect = allocateImage(*sprite);
if (rect.w == 0) {
if (debug::spriteWarnings) {
Log::Warning(Event::Sprite, "sprite atlas bitmap overflow");
@@ -230,8 +226,8 @@ optional<SpriteAtlasPosition> SpriteAtlas::getPosition(const std::string& name,
return SpriteAtlasPosition {
{{ float(spriteImage->getWidth()), spriteImage->getHeight() }},
- {{ float(rect.x + padding) / width, float(rect.y + padding) / height }},
- {{ float(rect.x + padding + w) / width, float(rect.y + padding + h) / height }}
+ {{ float(rect.x + padding) / size.width, float(rect.y + padding) / size.height }},
+ {{ float(rect.x + padding + w) / size.width, float(rect.y + padding + h) / size.height }}
};
}
@@ -264,29 +260,25 @@ void copyBitmap(const uint32_t *src, const uint32_t srcStride, const uint32_t sr
}
void SpriteAtlas::copy(const Holder& holder, const SpritePatternMode mode) {
- if (!data) {
- data = std::make_unique<uint32_t[]>(pixelWidth * pixelHeight);
- std::fill(data.get(), data.get() + pixelWidth * pixelHeight, 0);
+ if (!image.valid()) {
+ image = PremultipliedImage({ static_cast<uint32_t>(std::ceil(size.width * pixelRatio)),
+ static_cast<uint32_t>(std::ceil(size.height * pixelRatio)) });
+ std::fill(image.data.get(), image.data.get() + image.bytes(), 0);
}
- const uint32_t *srcData = reinterpret_cast<const uint32_t *>(holder.spriteImage->image.data.get());
+ const uint32_t* srcData =
+ reinterpret_cast<const uint32_t*>(holder.spriteImage->image.data.get());
if (!srcData) return;
- uint32_t *const dstData = data.get();
+ uint32_t* const dstData = reinterpret_cast<uint32_t*>(image.data.get());
const int padding = 1;
- copyBitmap(srcData, holder.spriteImage->image.size.width, 0, 0, dstData, pixelWidth,
+ copyBitmap(srcData, holder.spriteImage->image.size.width, 0, 0, dstData, image.size.width,
(holder.pos.x + padding) * pixelRatio, (holder.pos.y + padding) * pixelRatio,
- pixelWidth * pixelHeight, holder.spriteImage->image.size.width,
+ image.size.width * image.size.height, holder.spriteImage->image.size.width,
holder.spriteImage->image.size.height, mode);
- dirtyFlag = true;
-}
-
-void SpriteAtlas::upload(gl::Context& context, gl::TextureUnit unit) {
- if (dirtyFlag) {
- bind(false, context, unit);
- }
+ dirty = true;
}
void SpriteAtlas::updateDirty() {
@@ -317,77 +309,31 @@ void SpriteAtlas::updateDirty() {
dirtySprites.clear();
}
-void SpriteAtlas::bind(bool linear, gl::Context& context, gl::TextureUnit unit) {
- if (!data) {
- return; // Empty atlas
+void SpriteAtlas::upload(gl::Context& context, gl::TextureUnit unit) {
+ if (!texture) {
+ texture = context.createTexture(image, unit);
+ } else if (dirty) {
+ context.updateTexture(*texture, image, unit);
}
- if (!texture) {
- texture = context.createTexture();
- context.activeTexture = unit;
- context.texture[unit] = *texture;
#if not MBGL_USE_GLES2
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
+// if (dirty) {
+// platform::showColorDebugImage("Sprite Atlas",
+// reinterpret_cast<const char*>(image.data.get()), size.width,
+// size.height, image.size.width, image.size.height);
+// }
#endif // MBGL_USE_GLES2
- // We are using clamp to edge here since OpenGL ES doesn't allow GL_REPEAT on NPOT textures.
- // We use those when the pixelRatio isn't a power of two, e.g. on iPhone 6 Plus.
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
- fullUploadRequired = true;
- } else if (context.texture[unit] != *texture) {
- context.activeTexture = unit;
- context.texture[unit] = *texture;
- }
- GLuint filter_val = linear ? GL_LINEAR : GL_NEAREST;
- if (filter_val != filter) {
- context.activeTexture = unit;
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_val));
- MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_val));
- filter = filter_val;
- }
-
- if (dirtyFlag) {
- std::lock_guard<std::recursive_mutex> lock(mtx);
-
- context.activeTexture = unit;
- if (fullUploadRequired) {
- MBGL_CHECK_ERROR(glTexImage2D(
- GL_TEXTURE_2D, // GLenum target
- 0, // GLint level
- GL_RGBA, // GLint internalformat
- pixelWidth, // GLsizei width
- pixelHeight, // GLsizei height
- 0, // GLint border
- GL_RGBA, // GLenum format
- GL_UNSIGNED_BYTE, // GLenum type
- data.get() // const GLvoid * data
- ));
- fullUploadRequired = false;
- } else {
- MBGL_CHECK_ERROR(glTexSubImage2D(
- GL_TEXTURE_2D, // GLenum target
- 0, // GLint level
- 0, // GLint xoffset
- 0, // GLint yoffset
- pixelWidth, // GLsizei width
- pixelHeight, // GLsizei height
- GL_RGBA, // GLenum format
- GL_UNSIGNED_BYTE, // GLenum type
- data.get() // const GLvoid *pixels
- ));
- }
-
- dirtyFlag = false;
+ dirty = false;
+}
-#if not MBGL_USE_GLES2
- // platform::showColorDebugImage("Sprite Atlas", reinterpret_cast<const char*>(data.get()),
- // pixelWidth, pixelHeight, pixelWidth, pixelHeight);
-#endif // MBGL_USE_GLES2
- }
+void SpriteAtlas::bind(bool linear, gl::Context& context, gl::TextureUnit unit) {
+ upload(context, unit);
+ context.bindTexture(*texture, unit,
+ linear ? gl::TextureFilter::Linear : gl::TextureFilter::Nearest);
}
-SpriteAtlas::Holder::Holder(std::shared_ptr<const SpriteImage> spriteImage_, Rect<dimension> pos_)
+SpriteAtlas::Holder::Holder(std::shared_ptr<const SpriteImage> spriteImage_, Rect<uint16_t> pos_)
: spriteImage(std::move(spriteImage_)), pos(std::move(pos_)) {
}
diff --git a/src/mbgl/sprite/sprite_atlas.hpp b/src/mbgl/sprite/sprite_atlas.hpp
index 3e0ca51508..c79aec135e 100644
--- a/src/mbgl/sprite/sprite_atlas.hpp
+++ b/src/mbgl/sprite/sprite_atlas.hpp
@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/geometry/binpack.hpp>
-#include <mbgl/gl/object.hpp>
+#include <mbgl/gl/texture.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/optional.hpp>
#include <mbgl/sprite/sprite_image.hpp>
@@ -47,10 +47,9 @@ enum class SpritePatternMode : bool {
class SpriteAtlas : public util::noncopyable {
public:
- typedef uint16_t dimension;
using Sprites = std::map<std::string, std::shared_ptr<const SpriteImage>>;
- SpriteAtlas(dimension width, dimension height, float pixelRatio);
+ SpriteAtlas(Size, float pixelRatio);
~SpriteAtlas();
void load(const std::string& url, FileSource&);
@@ -93,21 +92,19 @@ public:
// the texture is only bound when the data is out of date (=dirty).
void upload(gl::Context&, gl::TextureUnit unit);
- dimension getWidth() const { return width; }
- dimension getHeight() const { return height; }
- dimension getTextureWidth() const { return pixelWidth; }
- dimension getTextureHeight() const { return pixelHeight; }
+ Size getSize() const { return size; }
float getPixelRatio() const { return pixelRatio; }
// Only for use in tests.
- const uint32_t* getData() const { return data.get(); }
+ const PremultipliedImage& getAtlasImage() const {
+ return image;
+ }
private:
void _setSprite(const std::string&, const std::shared_ptr<const SpriteImage>& = nullptr);
void emitSpriteLoadedIfComplete();
- const dimension width, height;
- const dimension pixelWidth, pixelHeight;
+ const Size size;
const float pixelRatio;
struct Loader;
@@ -127,26 +124,24 @@ private:
Sprites dirtySprites;
struct Holder : private util::noncopyable {
- Holder(std::shared_ptr<const SpriteImage>, Rect<dimension>);
+ Holder(std::shared_ptr<const SpriteImage>, Rect<uint16_t>);
Holder(Holder&&);
std::shared_ptr<const SpriteImage> spriteImage;
- const Rect<dimension> pos;
+ const Rect<uint16_t> pos;
};
using Key = std::pair<std::string, SpritePatternMode>;
- Rect<SpriteAtlas::dimension> allocateImage(const SpriteImage&);
+ Rect<uint16_t> allocateImage(const SpriteImage&);
void copy(const Holder& holder, SpritePatternMode mode);
std::recursive_mutex mtx;
- BinPack<dimension> bin;
+ BinPack<uint16_t> bin;
std::map<Key, Holder> images;
std::unordered_set<std::string> uninitialized;
- std::unique_ptr<uint32_t[]> data;
- std::atomic<bool> dirtyFlag;
- bool fullUploadRequired = true;
- mbgl::optional<gl::UniqueTexture> texture;
- uint32_t filter = 0;
+ PremultipliedImage image;
+ mbgl::optional<gl::Texture> texture;
+ std::atomic<bool> dirty;
static const int buffer = 1;
};