diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2016-10-26 16:39:25 -0700 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2016-11-01 18:41:52 +0100 |
commit | 9e3839781fdf1b1c6a2d61a5de9b2c7ddd68e9ed (patch) | |
tree | cde9eb4e99341e5200ca5a06a4a1d0fc602c9232 /src | |
parent | e2981c890e9a758c4dee703fa9e25e5d9eff65ce (diff) | |
download | qtlocation-mapboxgl-9e3839781fdf1b1c6a2d61a5de9b2c7ddd68e9ed.tar.gz |
[core] convert SpriteAtlas to use managed texture handling
Diffstat (limited to 'src')
-rw-r--r-- | src/mbgl/annotation/annotation_manager.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/gl/context.cpp | 12 | ||||
-rw-r--r-- | src/mbgl/gl/context.hpp | 7 | ||||
-rw-r--r-- | src/mbgl/renderer/painter_symbol.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/shader/symbol_uniforms.cpp | 12 | ||||
-rw-r--r-- | src/mbgl/shader/symbol_uniforms.hpp | 7 | ||||
-rw-r--r-- | src/mbgl/sprite/sprite_atlas.cpp | 126 | ||||
-rw-r--r-- | src/mbgl/sprite/sprite_atlas.hpp | 33 | ||||
-rw-r--r-- | src/mbgl/style/style.cpp | 2 |
9 files changed, 80 insertions, 125 deletions
diff --git a/src/mbgl/annotation/annotation_manager.cpp b/src/mbgl/annotation/annotation_manager.cpp index c7c13d0d2c..f8c1c3adf7 100644 --- a/src/mbgl/annotation/annotation_manager.cpp +++ b/src/mbgl/annotation/annotation_manager.cpp @@ -20,7 +20,7 @@ const std::string AnnotationManager::SourceID = "com.mapbox.annotations"; const std::string AnnotationManager::PointLayerID = "com.mapbox.annotations.points"; AnnotationManager::AnnotationManager(float pixelRatio) - : spriteAtlas(1024, 1024, pixelRatio) { + : spriteAtlas({ 1024, 1024 }, pixelRatio) { struct NullFileSource : public FileSource { std::unique_ptr<AsyncRequest> request(const Resource&, Callback) override { diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index acecf2b698..7200b75050 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -185,15 +185,21 @@ Framebuffer Context::createFramebuffer(const Texture& color) { UniqueTexture Context::createTexture(const Size size, const void* data, TextureUnit unit) { auto obj = createTexture(); - activeTexture = unit; - texture[unit] = obj; + updateTexture(obj, size, data, unit); + // 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)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); + return obj; +} + +void Context::updateTexture(TextureID id, const Size size, const void* data, TextureUnit unit) { + activeTexture = unit; + texture[unit] = id; MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width, size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data)); - return obj; } void Context::bindTexture(Texture& obj, diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index 84c83f8d31..ae2b71994f 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -68,6 +68,12 @@ public: return { image.size, createTexture(image.size, image.data.get(), unit) }; } + template <typename Image> + void updateTexture(Texture& obj, const Image& image, TextureUnit unit = 0) { + updateTexture(obj.texture.get(), image.size, image.data.get(), unit); + obj.size = image.size; + } + // Creates an empty texture with the specified dimensions. Texture createTexture(const Size size, TextureUnit unit = 0) { return { size, createTexture(size, nullptr, unit) }; @@ -148,6 +154,7 @@ private: UniqueBuffer createVertexBuffer(const void* data, std::size_t size); UniqueBuffer createIndexBuffer(const void* data, std::size_t size); UniqueTexture createTexture(Size size, const void* data, TextureUnit); + void updateTexture(TextureID, Size size, const void* data, TextureUnit); UniqueFramebuffer createFramebuffer(); UniqueRenderbuffer createRenderbuffer(RenderbufferType, Size size); diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp index d4ac5f94e9..a00389ce20 100644 --- a/src/mbgl/renderer/painter_symbol.cpp +++ b/src/mbgl/renderer/painter_symbol.cpp @@ -72,7 +72,7 @@ void Painter::renderSymbol(PaintParameters& parameters, const bool iconTransformed = values.rotationAlignment == AlignmentType::Map || state.getPitch() != 0; atlas.bind(bucket.sdfIcons || state.isChanging() || iconScaled || iconTransformed, context, 0); - std::array<uint16_t, 2> texsize {{ atlas.getWidth(), atlas.getHeight() }}; + const Size texsize = atlas.getSize(); if (bucket.sdfIcons) { if (values.hasHalo()) { @@ -101,7 +101,7 @@ void Painter::renderSymbol(PaintParameters& parameters, auto values = layer.impl->textPropertyValues(layout); - std::array<uint16_t, 2> texsize {{ glyphAtlas->width, glyphAtlas->height }}; + const Size texsize { glyphAtlas->width, glyphAtlas->height }; if (values.hasHalo()) { draw(parameters.shaders.symbolGlyph, diff --git a/src/mbgl/shader/symbol_uniforms.cpp b/src/mbgl/shader/symbol_uniforms.cpp index cd9f33de71..7071eff07c 100644 --- a/src/mbgl/shader/symbol_uniforms.cpp +++ b/src/mbgl/shader/symbol_uniforms.cpp @@ -9,7 +9,7 @@ using namespace style; template <class Values, class...Args> Values makeValues(const style::SymbolPropertyValues& values, - const std::array<uint16_t, 2>& texsize, + const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, const RenderTile& tile, const TransformState& state, @@ -35,7 +35,7 @@ Values makeValues(const style::SymbolPropertyValues& values, state), values.opacity, extrudeScale, - std::array<float, 2> {{ texsize[0] / 4.0f, texsize[1] / 4.0f }}, + std::array<float, 2> {{ float(texsize.width) / 4, float(texsize.height) / 4 }}, (state.getZoom() - zoomAdjust) * 10.0f, values.rotationAlignment == AlignmentType::Map, 0, @@ -46,7 +46,7 @@ Values makeValues(const style::SymbolPropertyValues& values, SymbolIconUniforms::Values SymbolIconUniforms::values(const style::SymbolPropertyValues& values, - const std::array<uint16_t, 2>& texsize, + const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, const RenderTile& tile, const TransformState& state) @@ -61,7 +61,7 @@ SymbolIconUniforms::values(const style::SymbolPropertyValues& values, } static SymbolSDFUniforms::Values makeSDFValues(const style::SymbolPropertyValues& values, - const std::array<uint16_t, 2>& texsize, + const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, const RenderTile& tile, const TransformState& state, @@ -95,7 +95,7 @@ static SymbolSDFUniforms::Values makeSDFValues(const style::SymbolPropertyValues SymbolSDFUniforms::Values SymbolSDFUniforms::haloValues(const style::SymbolPropertyValues& values, - const std::array<uint16_t, 2>& texsize, + const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, const RenderTile& tile, const TransformState& state, @@ -121,7 +121,7 @@ SymbolSDFUniforms::haloValues(const style::SymbolPropertyValues& values, SymbolSDFUniforms::Values SymbolSDFUniforms::foregroundValues(const style::SymbolPropertyValues& values, - const std::array<uint16_t, 2>& texsize, + const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, const RenderTile& tile, const TransformState& state, diff --git a/src/mbgl/shader/symbol_uniforms.hpp b/src/mbgl/shader/symbol_uniforms.hpp index dc1b25004f..a38837c051 100644 --- a/src/mbgl/shader/symbol_uniforms.hpp +++ b/src/mbgl/shader/symbol_uniforms.hpp @@ -1,6 +1,7 @@ #pragma once #include <mbgl/shader/uniforms.hpp> +#include <mbgl/util/size.hpp> #include <array> @@ -35,7 +36,7 @@ struct SymbolIconUniforms : gl::Uniforms< uniforms::u_fadetexture> { static Values values(const style::SymbolPropertyValues&, - const std::array<uint16_t, 2>& texsize, + const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, const RenderTile&, const TransformState&); @@ -59,14 +60,14 @@ struct SymbolSDFUniforms : gl::Uniforms< uniforms::u_pitch_with_map> { static Values haloValues(const style::SymbolPropertyValues&, - const std::array<uint16_t, 2>& texsize, + const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, const RenderTile&, const TransformState&, float pixelRatio); static Values foregroundValues(const style::SymbolPropertyValues&, - const std::array<uint16_t, 2>& texsize, + const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, const RenderTile&, const TransformState&, 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; }; diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index cec922f45e..c33a10517d 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -39,7 +39,7 @@ static Observer nullObserver; Style::Style(FileSource& fileSource_, float pixelRatio) : fileSource(fileSource_), glyphAtlas(std::make_unique<GlyphAtlas>(2048, 2048, fileSource)), - spriteAtlas(std::make_unique<SpriteAtlas>(1024, 1024, pixelRatio)), + spriteAtlas(std::make_unique<SpriteAtlas>(Size{ 1024, 1024 }, pixelRatio)), lineAtlas(std::make_unique<LineAtlas>(256, 512)), observer(&nullObserver) { glyphAtlas->setObserver(this); |