From 4f47cac04191d2ba98a6bfe450319447f8258d49 Mon Sep 17 00:00:00 2001 From: "r.kuznetsov" Date: Fri, 15 Feb 2019 11:29:02 +0300 Subject: [PATCH] [drape] Optimized font texture memory usage --- drape/drape_tests/font_texture_tests.cpp | 5 +- drape/font_texture.cpp | 23 +++--- drape/glyph_manager.cpp | 2 +- drape/texture_manager.cpp | 91 ++---------------------- drape/texture_manager.hpp | 32 ++------- 5 files changed, 28 insertions(+), 125 deletions(-) diff --git a/drape/drape_tests/font_texture_tests.cpp b/drape/drape_tests/font_texture_tests.cpp index b6f9eca021..6d03cfde8c 100644 --- a/drape/drape_tests/font_texture_tests.cpp +++ b/drape/drape_tests/font_texture_tests.cpp @@ -94,9 +94,10 @@ UNIT_TEST(UploadingGlyphs) args.m_blacklist = "fonts_blacklist.txt"; GetPlatform().GetFontNames(args.m_fonts); + uint32_t constexpr kTextureSize = 1024; GlyphGenerator glyphGenerator(4); GlyphManager mng(args); - DummyGlyphIndex index(m2::PointU(128, 128), make_ref(&mng), make_ref(&glyphGenerator)); + DummyGlyphIndex index(m2::PointU(kTextureSize, kTextureSize), make_ref(&mng), make_ref(&glyphGenerator)); size_t count = 1; // invalid symbol glyph has mapped internally. count += (index.MapResource(GlyphKey(0x58, GlyphManager::kDynamicGlyphSize)) != nullptr) ? 1 : 0; count += (index.MapResource(GlyphKey(0x59, GlyphManager::kDynamicGlyphSize)) != nullptr) ? 1 : 0; @@ -108,7 +109,7 @@ UNIT_TEST(UploadingGlyphs) Texture::Params p; p.m_allocator = GetDefaultAllocator(make_ref(&context)); p.m_format = dp::TextureFormat::Alpha; - p.m_width = p.m_height = 128; + p.m_width = p.m_height = kTextureSize; DummyTexture tex; tex.Create(make_ref(&context), p); diff --git a/drape/font_texture.cpp b/drape/font_texture.cpp index 17a5fb9bf4..b19dd1a45c 100644 --- a/drape/font_texture.cpp +++ b/drape/font_texture.cpp @@ -97,11 +97,15 @@ GlyphIndex::GlyphIndex(m2::PointU const & size, ref_ptr mng, ASSERT(m_generator != nullptr, ()); m_generator->RegisterListener(make_ref(this)); - // Cache invalid glyph. - auto const key = GlyphKey(m_mng->GetInvalidGlyph(GlyphManager::kDynamicGlyphSize).m_code, - GlyphManager::kDynamicGlyphSize); + // Cache predefined glyphs. bool newResource = false; - MapResource(key, newResource); + uint32_t constexpr kPredefinedGlyphsCount = 128; + for (uint32_t i = 0; i < kPredefinedGlyphsCount; ++i) + { + auto const key = GlyphKey(i, GlyphManager::kDynamicGlyphSize); + + MapResource(key, newResource); + } } GlyphIndex::~GlyphIndex() @@ -162,12 +166,15 @@ ref_ptr GlyphIndex::MapResource(GlyphKey const & key, boo GlyphManager::Glyph glyph = m_mng->GetGlyph(key.GetUnicodePoint(), key.GetFixedSize()); m2::RectU r; - if (!m_packer.PackGlyph(glyph.m_image.m_width, glyph.m_image.m_height, r)) + if (!glyph.m_metrics.m_isValid || !m_packer.PackGlyph(glyph.m_image.m_width, glyph.m_image.m_height, r)) { glyph.m_image.Destroy(); - LOG(LWARNING, ("Glyphs packer could not pack a glyph", key.GetUnicodePoint(), - "w =", glyph.m_image.m_width, "h =", glyph.m_image.m_height, - "packerSize =", m_packer.GetSize())); + if (glyph.m_metrics.m_isValid) + { + LOG(LWARNING, ("Glyphs packer could not pack a glyph", key.GetUnicodePoint(), + "w =", glyph.m_image.m_width, "h =", glyph.m_image.m_height, + "packerSize =", m_packer.GetSize())); + } auto const invalidGlyph = m_mng->GetInvalidGlyph(key.GetFixedSize()); auto invalidGlyphIndex = m_index.find(GlyphKey(invalidGlyph.m_code, key.GetFixedSize())); diff --git a/drape/glyph_manager.cpp b/drape/glyph_manager.cpp index e1d88f6cfd..3144308249 100644 --- a/drape/glyph_manager.cpp +++ b/drape/glyph_manager.cpp @@ -649,7 +649,7 @@ bool GlyphManager::AreGlyphsReady(strings::UniString const & str, int fixedSize) GlyphManager::Glyph GlyphManager::GetInvalidGlyph(int fixedSize) const { - strings::UniChar const kInvalidGlyphCode = 0x9; + strings::UniChar constexpr kInvalidGlyphCode = 0x9; int const kFontId = 0; static bool s_inited = false; diff --git a/drape/texture_manager.cpp b/drape/texture_manager.cpp index 2276b9e807..c7c8f22d6c 100644 --- a/drape/texture_manager.cpp +++ b/drape/texture_manager.cpp @@ -30,11 +30,9 @@ uint32_t const kMaxTextureSize = 1024; uint32_t const kStippleTextureWidth = 512; uint32_t const kMinStippleTextureHeight = 64; uint32_t const kMinColorTextureSize = 32; +uint32_t const kGlyphsTextureSize = 1024; size_t const kInvalidGlyphGroup = std::numeric_limits::max(); -// number of glyphs (since 0) which will be in each texture -size_t const kDuplicatedGlyphsCount = 128; - uint32_t const kReservedPatterns = 10; size_t const kReservedColors = 20; @@ -237,7 +235,6 @@ uint32_t TextureManager::StippleRegion::GetPatternPixelLength() const void TextureManager::Release() { - m_glyphGroups.clear(); m_hybridGlyphGroups.clear(); m_symbolTextures.clear(); @@ -303,7 +300,7 @@ bool TextureManager::HasAsyncRoutines() const ref_ptr TextureManager::AllocateGlyphTexture() { std::lock_guard lock(m_glyphTexturesMutex); - m2::PointU size(m_maxTextureSize, m_maxTextureSize); + m2::PointU size(kGlyphsTextureSize, kGlyphsTextureSize); m_glyphTextures.push_back(make_unique_dp(size, make_ref(m_glyphManager), m_glyphGenerator, make_ref(m_textureAllocator))); @@ -350,67 +347,6 @@ void TextureManager::GetGlyphsRegions(ref_ptr tex, strings::UniStri m_nothingToUpload.clear(); } -size_t TextureManager::FindGlyphsGroup(strings::UniChar const & c) const -{ - auto const iter = std::lower_bound(m_glyphGroups.begin(), m_glyphGroups.end(), c, - [](GlyphGroup const & g, strings::UniChar const & c) - { - return g.m_endChar < c; - }); - - if (iter == m_glyphGroups.end()) - return kInvalidGlyphGroup; - - return static_cast(std::distance(m_glyphGroups.begin(), iter)); -} - -size_t TextureManager::FindGlyphsGroup(strings::UniString const & text) const -{ - size_t groupIndex = kInvalidGlyphGroup; - for (auto const & c : text) - { - // Skip glyphs which can be duplicated. - if (c < kDuplicatedGlyphsCount) - continue; - - size_t currentIndex = FindGlyphsGroup(c); - - // an invalid glyph found - if (currentIndex == kInvalidGlyphGroup) - { -#if defined(TRACK_GLYPH_USAGE) - GlyphUsageTracker::Instance().AddInvalidGlyph(text, c); -#endif - return kInvalidGlyphGroup; - } - - // Check if each glyph in text id in one group. - if (groupIndex == kInvalidGlyphGroup) - groupIndex = currentIndex; - else if (groupIndex != currentIndex) - { -#if defined(TRACK_GLYPH_USAGE) - GlyphUsageTracker::Instance().AddUnexpectedGlyph(text, c, currentIndex, groupIndex); -#endif - return kInvalidGlyphGroup; - } - } - - // All glyphs in duplicated range. - if (groupIndex == kInvalidGlyphGroup) - groupIndex = FindGlyphsGroup(text[0]); - - return groupIndex; -} - -size_t TextureManager::FindGlyphsGroup(TMultilineText const & text) const -{ - strings::UniString combinedString; - MultilineTextToUniString(text, combinedString); - - return FindGlyphsGroup(combinedString); -} - uint32_t TextureManager::GetNumberOfUnfoundCharacters(strings::UniString const & text, int fixedHeight, HybridGlyphGroup const & group) const { @@ -453,8 +389,10 @@ size_t TextureManager::FindHybridGlyphsGroup(strings::UniString const & text, in // Looking for a hybrid texture which contains text entirely. for (size_t i = 0; i < m_hybridGlyphGroups.size() - 1; i++) + { if (GetNumberOfUnfoundCharacters(text, fixedHeight, m_hybridGlyphGroups[i]) == 0) return i; + } // Check if we can contain text in the last hybrid texture. uint32_t const unfoundChars = GetNumberOfUnfoundCharacters(text, fixedHeight, group); @@ -539,30 +477,11 @@ void TextureManager::Init(ref_ptr context, Params const & p // Initialize glyphs. m_glyphManager = make_unique_dp(params.m_glyphMngParams); - - uint32_t const textureSquare = m_maxTextureSize * m_maxTextureSize; + uint32_t const textureSquare = kGlyphsTextureSize * kGlyphsTextureSize; uint32_t const baseGlyphHeight = static_cast(params.m_glyphMngParams.m_baseGlyphHeight * kGlyphAreaMultiplier); uint32_t const averageGlyphSquare = baseGlyphHeight * baseGlyphHeight; - - m_glyphGroups.push_back(GlyphGroup()); m_maxGlypsCount = static_cast(ceil(kGlyphAreaCoverage * textureSquare / averageGlyphSquare)); - m_glyphManager->ForEachUnicodeBlock([this](strings::UniChar const & start, strings::UniChar const & end) - { - if (m_glyphGroups.empty()) - { - m_glyphGroups.push_back(GlyphGroup(start, end)); - return; - } - - GlyphGroup & group = m_glyphGroups.back(); - ASSERT_LESS_OR_EQUAL(group.m_endChar, start, ()); - - if (end - group.m_startChar < m_maxGlypsCount) - group.m_endChar = end; - else - m_glyphGroups.push_back(GlyphGroup(start, end)); - }); m_nothingToUpload.clear(); } diff --git a/drape/texture_manager.hpp b/drape/texture_manager.hpp index d4ebe155f7..624f0a980f 100644 --- a/drape/texture_manager.hpp +++ b/drape/texture_manager.hpp @@ -150,10 +150,6 @@ private: void GetGlyphsRegions(ref_ptr tex, strings::UniString const & text, int fixedHeight, TGlyphsBuffer & regions); - size_t FindGlyphsGroup(strings::UniChar const & c) const; - size_t FindGlyphsGroup(strings::UniString const & text) const; - size_t FindGlyphsGroup(TMultilineText const & text) const; - size_t FindHybridGlyphsGroup(strings::UniString const & text, int fixedHeight); size_t FindHybridGlyphsGroup(TMultilineText const & text, int fixedHeight); @@ -198,29 +194,10 @@ private: template void CalcGlyphRegions(TText const & text, int fixedHeight, TBuffer & buffers) { - size_t const groupIndex = FindGlyphsGroup(text); - bool useHybridGroup = false; - if (fixedHeight < 0 && groupIndex != GetInvalidGlyphGroup()) - { - GlyphGroup & group = m_glyphGroups[groupIndex]; - uint32_t const absentGlyphs = GetAbsentGlyphsCount(group.m_texture, text, fixedHeight); - if (group.m_texture == nullptr || group.m_texture->HasEnoughSpace(absentGlyphs)) - FillResults(text, fixedHeight, buffers, group); - else - useHybridGroup = true; - } - else - { - useHybridGroup = true; - } - - if (useHybridGroup) - { - size_t const hybridGroupIndex = FindHybridGlyphsGroup(text, fixedHeight); - ASSERT(hybridGroupIndex != GetInvalidGlyphGroup(), ()); - HybridGlyphGroup & group = m_hybridGlyphGroups[hybridGroupIndex]; - FillResults(text, fixedHeight, buffers, group); - } + size_t const hybridGroupIndex = FindHybridGlyphsGroup(text, fixedHeight); + ASSERT(hybridGroupIndex != GetInvalidGlyphGroup(), ()); + HybridGlyphGroup & group = m_hybridGlyphGroups[hybridGroupIndex]; + FillResults(text, fixedHeight, buffers, group); } uint32_t GetAbsentGlyphsCount(ref_ptr texture, strings::UniString const & text, @@ -250,7 +227,6 @@ private: drape_ptr m_glyphManager; drape_ptr m_textureAllocator; - buffer_vector m_glyphGroups; buffer_vector m_hybridGlyphGroups; base::Timer m_uploadTimer;