diff --git a/drape/font_texture.cpp b/drape/font_texture.cpp index 1c6b5e68fa..993e050a27 100644 --- a/drape/font_texture.cpp +++ b/drape/font_texture.cpp @@ -10,6 +10,7 @@ #include "base/stl_add.hpp" #include +#include using namespace std::placeholders; @@ -94,7 +95,7 @@ void GlyphGenerator::GenerateGlyphTask::Run(uint32_t sdfScale) return; auto const g = GlyphManager::GenerateGlyph(data.m_glyph, sdfScale); - data.m_glyph.m_image.Destroy(); + data.DestroyGlyph(); m_generatedGlyphs.emplace_back(GlyphGenerator::GlyphGenerationData{data.m_rect, g}); } } @@ -102,10 +103,10 @@ void GlyphGenerator::GenerateGlyphTask::Run(uint32_t sdfScale) void GlyphGenerator::GenerateGlyphTask::DestroyAllGlyphs() { for (auto & data : m_glyphs) - data.m_glyph.m_image.Destroy(); + data.DestroyGlyph(); for (auto & data : m_generatedGlyphs) - data.m_glyph.m_image.Destroy(); + data.DestroyGlyph(); } GlyphGenerator::GlyphGenerator(uint32_t sdfScale, @@ -129,7 +130,7 @@ GlyphGenerator::~GlyphGenerator() std::lock_guard lock(m_mutex); for (auto & data : m_queue) - data.m_glyph.m_image.Destroy(); + data.DestroyGlyph(); m_queue.clear(); } @@ -140,16 +141,27 @@ bool GlyphGenerator::IsSuspended() const } void GlyphGenerator::GenerateGlyph(m2::RectU const & rect, GlyphManager::Glyph & glyph) +{ + GenerateGlyph(GlyphGenerationData(rect, glyph)); +} + +void GlyphGenerator::GenerateGlyph(GlyphGenerationData && data) +{ + GenerateGlyphs({std::move(data)}); +} + +void GlyphGenerator::GenerateGlyphs(GlyphGenerationDataArray && generationData) { std::lock_guard lock(m_mutex); if (!m_completionHandler) { - glyph.m_image.Destroy(); + for (auto & data : generationData) + data.DestroyGlyph(); return; } - std::list queue; - m_queue.emplace_back(rect, glyph); + GlyphGenerationDataArray queue; + std::move(generationData.begin(), generationData.end(), std::back_inserter(m_queue)); std::swap(m_queue, queue); m_glyphsCounter += queue.size(); @@ -175,7 +187,7 @@ void GlyphGenerator::OnTaskFinished(std::shared_ptr const & t return; } - std::vector glyphs = task->StealGeneratedGlyphs(); + auto glyphs = task->StealGeneratedGlyphs(); std::lock_guard lock(m_mutex); ASSERT_GREATER_OR_EQUAL(m_glyphsCounter, glyphs.size(), ()); @@ -209,6 +221,43 @@ GlyphIndex::~GlyphIndex() } ref_ptr GlyphIndex::MapResource(GlyphKey const & key, bool & newResource) +{ + GlyphGenerator::GlyphGenerationData data; + auto result = MapResource(key, newResource, data); + if (result != nullptr && newResource) + m_generator->GenerateGlyph(data.m_rect, data.m_glyph); + return result; +} + +std::vector> GlyphIndex::MapResources(std::vector const & keys, + bool & hasNewResources) +{ + GlyphGenerator::GlyphGenerationDataArray dataArray; + dataArray.reserve(keys.size()); + + std::vector> info; + info.reserve(keys.size()); + + hasNewResources = false; + for (auto const & glyphKey : keys) + { + bool newResource = false; + GlyphGenerator::GlyphGenerationData data; + auto result = MapResource(glyphKey, newResource, data); + hasNewResources |= newResource; + if (result != nullptr && newResource) + dataArray.push_back(std::move(data)); + info.push_back(std::move(result)); + } + + if (!dataArray.empty()) + m_generator->GenerateGlyphs(std::move(dataArray)); + + return info; +} + +ref_ptr GlyphIndex::MapResource(GlyphKey const & key, bool & newResource, + GlyphGenerator::GlyphGenerationData & generationData) { newResource = false; auto it = m_index.find(key); @@ -226,15 +275,19 @@ ref_ptr GlyphIndex::MapResource(GlyphKey const & key, boo "w =", glyph.m_image.m_width, "h =", glyph.m_image.m_height, "packerSize =", m_packer.GetSize())); - auto invalidGlyph = m_index.find(GlyphKey(m_mng->GetInvalidGlyph(key.GetFixedSize()).m_code, - key.GetFixedSize())); - if (invalidGlyph != m_index.end()) - return make_ref(&invalidGlyph->second); + auto const invalidGlyph = m_mng->GetInvalidGlyph(key.GetFixedSize()); + auto invalidGlyphIndex = m_index.find(GlyphKey(invalidGlyph.m_code, key.GetFixedSize())); + if (invalidGlyphIndex != m_index.end()) + { + generationData.m_glyph = invalidGlyph; + generationData.m_rect = r; + return make_ref(&invalidGlyphIndex->second); + } return nullptr; } - - m_generator->GenerateGlyph(r, glyph); + generationData.m_glyph = glyph; + generationData.m_rect = r; auto res = m_index.emplace(key, GlyphInfo(m_packer.MapTextureCoords(r), glyph.m_metrics)); ASSERT(res.second, ()); @@ -265,7 +318,7 @@ size_t GlyphIndex::GetPendingNodesCount() return m_pendingNodes.size(); } -void GlyphIndex::OnGlyphGenerationCompletion(std::vector && glyphs) +void GlyphIndex::OnGlyphGenerationCompletion(GlyphGenerator::GlyphGenerationDataArray && glyphs) { std::lock_guard lock(m_mutex); for (auto & g : glyphs) diff --git a/drape/font_texture.hpp b/drape/font_texture.hpp index fc59ed8697..2b2ed09d8e 100644 --- a/drape/font_texture.hpp +++ b/drape/font_texture.hpp @@ -7,7 +7,6 @@ #include "drape/texture.hpp" #include -#include #include #include #include @@ -83,37 +82,47 @@ public: m2::RectU m_rect; GlyphManager::Glyph m_glyph; + GlyphGenerationData() = default; GlyphGenerationData(m2::RectU const & rect, GlyphManager::Glyph const & glyph) : m_rect(rect), m_glyph(glyph) {} + + void DestroyGlyph() + { + m_glyph.m_image.Destroy(); + } }; + using GlyphGenerationDataArray = std::vector; + class GenerateGlyphTask { public: - explicit GenerateGlyphTask(std::list && glyphs) + explicit GenerateGlyphTask(GlyphGenerationDataArray && glyphs) : m_glyphs(std::move(glyphs)) , m_isCancelled(false) {} void Run(uint32_t sdfScale); void Cancel() { m_isCancelled = true; } - std::vector && StealGeneratedGlyphs() { return std::move(m_generatedGlyphs); } + GlyphGenerationDataArray && StealGeneratedGlyphs() { return std::move(m_generatedGlyphs); } bool IsCancelled() const { return m_isCancelled; } void DestroyAllGlyphs(); private: - std::list m_glyphs; - std::vector m_generatedGlyphs; + GlyphGenerationDataArray m_glyphs; + GlyphGenerationDataArray m_generatedGlyphs; std::atomic m_isCancelled; }; - using CompletionHandler = std::function &&)>; + using CompletionHandler = std::function; GlyphGenerator(uint32_t sdfScale, CompletionHandler const & completionHandler); ~GlyphGenerator(); void GenerateGlyph(m2::RectU const & rect, GlyphManager::Glyph & glyph); + void GenerateGlyph(GlyphGenerationData && data); + void GenerateGlyphs(GlyphGenerationDataArray && generationData); bool IsSuspended() const; private: @@ -123,7 +132,7 @@ private: CompletionHandler m_completionHandler; ActiveTasks m_activeTasks; - std::list m_queue; + GlyphGenerationDataArray m_queue; size_t m_glyphsCounter = 0; mutable std::mutex m_mutex; }; @@ -136,6 +145,8 @@ public: // This function can return nullptr. ref_ptr MapResource(GlyphKey const & key, bool & newResource); + std::vector> MapResources(std::vector const & keys, + bool & hasNewResources); void UploadResources(ref_ptr texture); bool CanBeGlyphPacked(uint32_t glyphsCount) const; @@ -148,6 +159,8 @@ public: size_t GetPendingNodesCount(); private: + ref_ptr MapResource(GlyphKey const & key, bool & newResource, + GlyphGenerator::GlyphGenerationData & generationData); void OnGlyphGenerationCompletion(std::vector && glyphs); GlyphPacker m_packer; @@ -178,6 +191,13 @@ public: ~FontTexture() override { TBase::Reset(); } + std::vector> FindResources(std::vector const & keys, + bool & hasNewResources) + { + ASSERT(m_indexer != nullptr, ()); + return m_indexer->MapResources(keys, hasNewResources); + } + bool HasEnoughSpace(uint32_t newKeysCount) const override { return m_index.CanBeGlyphPacked(newKeysCount); diff --git a/drape/texture_manager.cpp b/drape/texture_manager.cpp index 7025a82b21..9b17445644 100644 --- a/drape/texture_manager.cpp +++ b/drape/texture_manager.cpp @@ -304,6 +304,35 @@ void TextureManager::GetRegionBase(ref_ptr tex, TextureManager::BaseReg m_nothingToUpload.clear(); } +void TextureManager::GetGlyphsRegions(ref_ptr tex, strings::UniString const & text, + int fixedHeight, TGlyphsBuffer & regions) +{ + ASSERT(tex != nullptr, ()); + + std::vector keys; + keys.reserve(text.size()); + for (auto const & c : text) + keys.emplace_back(GlyphKey(c, fixedHeight)); + + bool hasNew = false; + auto resourcesInfo = tex->FindResources(keys, hasNew); + ASSERT_EQUAL(text.size(), resourcesInfo.size(), ()); + + regions.reserve(resourcesInfo.size()); + for (auto const & info : resourcesInfo) + { + GlyphRegion reg; + reg.SetResourceInfo(info); + reg.SetTexture(tex); + ASSERT(reg.IsValid(), ()); + + regions.push_back(std::move(reg)); + } + + if (hasNew) + 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, diff --git a/drape/texture_manager.hpp b/drape/texture_manager.hpp index 444a889efd..57d8ed5e9b 100644 --- a/drape/texture_manager.hpp +++ b/drape/texture_manager.hpp @@ -143,6 +143,9 @@ private: ref_ptr AllocateGlyphTexture(); void GetRegionBase(ref_ptr tex, TextureManager::BaseRegion & region, Texture::Key const & key); + 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; @@ -164,13 +167,7 @@ private: if (group.m_texture == nullptr) group.m_texture = AllocateGlyphTexture(); - regions.reserve(text.size()); - for (strings::UniChar const & c : text) - { - GlyphRegion reg; - GetRegionBase(group.m_texture, reg, GlyphKey(c, fixedHeight)); - regions.push_back(reg); - } + GetGlyphsRegions(group.m_texture, text, fixedHeight, regions); } template