From dc1861f6d5391707126a20dbb0272f5bd3522de8 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Thu, 15 Sep 2016 17:03:13 -0700 Subject: [core] Merge GlyphStore and GlyphAtlas --- src/mbgl/geometry/glyph_atlas.cpp | 201 -------------------------------------- src/mbgl/geometry/glyph_atlas.hpp | 64 ------------ 2 files changed, 265 deletions(-) delete mode 100644 src/mbgl/geometry/glyph_atlas.cpp delete mode 100644 src/mbgl/geometry/glyph_atlas.hpp (limited to 'src/mbgl/geometry') diff --git a/src/mbgl/geometry/glyph_atlas.cpp b/src/mbgl/geometry/glyph_atlas.cpp deleted file mode 100644 index ff62c5b897..0000000000 --- a/src/mbgl/geometry/glyph_atlas.cpp +++ /dev/null @@ -1,201 +0,0 @@ -#include - -#include -#include -#include -#include -#include - -#include -#include - - -namespace mbgl { - -GlyphAtlas::GlyphAtlas(uint16_t width_, uint16_t height_) - : width(width_), - height(height_), - bin(width_, height_), - data(std::make_unique(width_ * height_)), - dirty(true) { -} - -GlyphAtlas::~GlyphAtlas() = default; - -void GlyphAtlas::addGlyphs(uintptr_t tileUID, - const std::u32string& text, - const FontStack& fontStack, - const GlyphSet& glyphSet, - GlyphPositions& face) -{ - std::lock_guard lock(mtx); - - const std::map& sdfs = glyphSet.getSDFs(); - - for (uint32_t chr : text) - { - auto sdf_it = sdfs.find(chr); - if (sdf_it == sdfs.end()) { - continue; - } - - const SDFGlyph& sdf = sdf_it->second; - Rect rect = addGlyph(tileUID, fontStack, sdf); - face.emplace(chr, Glyph{rect, sdf.metrics}); - } -} - -Rect GlyphAtlas::addGlyph(uintptr_t tileUID, - const FontStack& fontStack, - const SDFGlyph& glyph) -{ - // Use constant value for now. - const uint8_t buffer = 3; - - std::map& face = index[fontStack]; - auto it = face.find(glyph.id); - - // The glyph is already in this texture. - if (it != face.end()) { - GlyphValue& value = it->second; - value.ids.insert(tileUID); - return value.rect; - } - - // The glyph bitmap has zero width. - if (glyph.bitmap.empty()) { - return Rect{ 0, 0, 0, 0 }; - } - - uint16_t buffered_width = glyph.metrics.width + buffer * 2; - uint16_t buffered_height = glyph.metrics.height + buffer * 2; - - // Add a 1px border around every image. - const uint16_t padding = 1; - uint16_t pack_width = buffered_width + 2 * padding; - uint16_t pack_height = buffered_height + 2 * padding; - - // Increase to next number divisible by 4, but at least 1. - // This is so we can scale down the texture coordinates and pack them - // into 2 bytes rather than 4 bytes. - pack_width += (4 - pack_width % 4); - pack_height += (4 - pack_height % 4); - - Rect rect = bin.allocate(pack_width, pack_height); - if (rect.w == 0) { - Log::Error(Event::OpenGL, "glyph bitmap overflow"); - return rect; - } - - assert(rect.x + rect.w <= width); - assert(rect.y + rect.h <= height); - - face.emplace(glyph.id, GlyphValue { rect, tileUID }); - - // Copy the bitmap - const uint8_t* source = reinterpret_cast(glyph.bitmap.data()); - for (uint32_t y = 0; y < buffered_height; y++) { - uint32_t y1 = width * (rect.y + y + padding) + rect.x + padding; - uint32_t y2 = buffered_width * y; - for (uint32_t x = 0; x < buffered_width; x++) { - data[y1 + x] = source[y2 + x]; - } - } - - dirty = true; - - return rect; -} - -void GlyphAtlas::removeGlyphs(uintptr_t tileUID) { - std::lock_guard lock(mtx); - - for (auto& faces : index) { - std::map& face = faces.second; - for (auto it = face.begin(); it != face.end(); /* we advance in the body */) { - GlyphValue& value = it->second; - value.ids.erase(tileUID); - - if (value.ids.empty()) { - const Rect& rect = value.rect; - - // Clear out the bitmap. - uint8_t *target = data.get(); - for (uint32_t y = 0; y < rect.h; y++) { - uint32_t y1 = width * (rect.y + y) + rect.x; - for (uint32_t x = 0; x < rect.w; x++) { - target[y1 + x] = 0; - } - } - - bin.release(rect); - - // Make sure to post-increment the iterator: This will return the - // current iterator, but will go to the next position before we - // erase the element from the map. That way, the iterator stays - // valid. - face.erase(it++); - } else { - ++it; - } - } - } -} - -void GlyphAtlas::upload(gl::ObjectStore& store, gl::Config& config, uint32_t unit) { - if (dirty) { - const bool first = !texture; - bind(store, config, unit); - - std::lock_guard lock(mtx); - - config.activeTexture = unit; - if (first) { - MBGL_CHECK_ERROR(glTexImage2D( - GL_TEXTURE_2D, // GLenum target - 0, // GLint level - GL_ALPHA, // GLint internalformat - width, // GLsizei width - height, // GLsizei height - 0, // GLint border - GL_ALPHA, // GLenum format - GL_UNSIGNED_BYTE, // GLenum type - data.get() // const GLvoid* data - )); - } else { - MBGL_CHECK_ERROR(glTexSubImage2D( - GL_TEXTURE_2D, // GLenum target - 0, // GLint level - 0, // GLint xoffset - 0, // GLint yoffset - width, // GLsizei width - height, // GLsizei height - GL_ALPHA, // GLenum format - GL_UNSIGNED_BYTE, // GLenum type - data.get() // const GLvoid* data - )); - } - - dirty = false; - } -} - -void GlyphAtlas::bind(gl::ObjectStore& store, gl::Config& config, uint32_t unit) { - if (!texture) { - texture = store.createTexture(); - config.activeTexture = unit; - config.texture[unit] = *texture; -#ifndef GL_ES_VERSION_2_0 - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); -#endif - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - 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)); - } else if (config.texture[unit] != *texture) { - config.activeTexture = unit; - config.texture[unit] = *texture; - } -} - -} // namespace mbgl diff --git a/src/mbgl/geometry/glyph_atlas.hpp b/src/mbgl/geometry/glyph_atlas.hpp deleted file mode 100644 index b9170c1caf..0000000000 --- a/src/mbgl/geometry/glyph_atlas.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace mbgl { - -namespace gl { -class Config; -} // namespace gl - -class GlyphAtlas : public util::noncopyable { -public: - GlyphAtlas(uint16_t width, uint16_t height); - ~GlyphAtlas(); - - void addGlyphs(uintptr_t tileUID, - const std::u32string& text, - const FontStack&, - const GlyphSet&, - GlyphPositions&); - void removeGlyphs(uintptr_t tileUID); - - // Binds the atlas texture to the GPU, and uploads data if it is out of date. - void bind(gl::ObjectStore&, gl::Config&, uint32_t unit); - - // Uploads the texture to the GPU to be available when we need it. This is a lazy operation; - // the texture is only bound when the data is out of date (=dirty). - void upload(gl::ObjectStore&, gl::Config&, uint32_t unit); - - const GLsizei width; - const GLsizei height; - -private: - struct GlyphValue { - GlyphValue(Rect rect_, uintptr_t id) - : rect(std::move(rect_)), ids({ id }) {} - Rect rect; - std::set ids; - }; - - Rect addGlyph(uintptr_t tileID, - const FontStack&, - const SDFGlyph&); - - std::mutex mtx; - BinPack bin; - std::unordered_map, FontStackHash> index; - const std::unique_ptr data; - std::atomic dirty; - mbgl::optional texture; -}; - -} // namespace mbgl -- cgit v1.2.1