diff options
author | r.kuznetsov <r.kuznetsov@corp.mail.ru> | 2018-02-15 13:16:26 +0300 |
---|---|---|
committer | Daria Volvenkova <d.volvenkova@corp.mail.ru> | 2018-02-16 13:20:29 +0300 |
commit | b7a874d09d583864b7e1b7b84cf0de26a05c3d50 (patch) | |
tree | 248e3608f666da78a87115100877f943aabe060f /drape | |
parent | 295ab3b25515bafcadcf65b34929e674b62ba43f (diff) |
Extracted glyph generator from font textures
Diffstat (limited to 'drape')
-rw-r--r-- | drape/CMakeLists.txt | 2 | ||||
-rw-r--r-- | drape/font_texture.cpp | 134 | ||||
-rw-r--r-- | drape/font_texture.hpp | 88 | ||||
-rw-r--r-- | drape/glyph_generator.cpp | 131 | ||||
-rw-r--r-- | drape/glyph_generator.hpp | 88 | ||||
-rw-r--r-- | drape/texture.hpp | 1 | ||||
-rw-r--r-- | drape/texture_manager.cpp | 14 | ||||
-rw-r--r-- | drape/texture_manager.hpp | 6 |
8 files changed, 250 insertions, 214 deletions
diff --git a/drape/CMakeLists.txt b/drape/CMakeLists.txt index 9552fdd0be..2157d97188 100644 --- a/drape/CMakeLists.txt +++ b/drape/CMakeLists.txt @@ -55,6 +55,8 @@ set( ${DRAPE_ROOT}/glsl_types.hpp ${DRAPE_ROOT}/glstate.cpp ${DRAPE_ROOT}/glstate.hpp + ${DRAPE_ROOT}/glyph_generator.cpp + ${DRAPE_ROOT}/glyph_generator.hpp ${DRAPE_ROOT}/glyph_manager.cpp ${DRAPE_ROOT}/glyph_manager.hpp ${DRAPE_ROOT}/gpu_buffer.cpp diff --git a/drape/font_texture.cpp b/drape/font_texture.cpp index 993e050a27..ff4ccca422 100644 --- a/drape/font_texture.cpp +++ b/drape/font_texture.cpp @@ -86,123 +86,16 @@ m2::RectF GlyphPacker::MapTextureCoords(const m2::RectU & pixelRect) const bool GlyphPacker::IsFull() const { return m_isFull; } -void GlyphGenerator::GenerateGlyphTask::Run(uint32_t sdfScale) -{ - m_generatedGlyphs.reserve(m_glyphs.size()); - for (auto & data : m_glyphs) - { - if (m_isCancelled) - return; - - auto const g = GlyphManager::GenerateGlyph(data.m_glyph, sdfScale); - data.DestroyGlyph(); - m_generatedGlyphs.emplace_back(GlyphGenerator::GlyphGenerationData{data.m_rect, g}); - } -} - -void GlyphGenerator::GenerateGlyphTask::DestroyAllGlyphs() -{ - for (auto & data : m_glyphs) - data.DestroyGlyph(); - - for (auto & data : m_generatedGlyphs) - data.DestroyGlyph(); -} - -GlyphGenerator::GlyphGenerator(uint32_t sdfScale, - CompletionHandler const & completionHandler) - : m_sdfScale(sdfScale) - , m_completionHandler(completionHandler) -{ - ASSERT(m_completionHandler != nullptr, ()); -} - -GlyphGenerator::~GlyphGenerator() -{ - { - std::lock_guard<std::mutex> lock(m_mutex); - m_completionHandler = nullptr; - } - - // Here we have to wait for active tasks completion, - // because they capture 'this' pointer. - m_activeTasks.FinishAll(); - - std::lock_guard<std::mutex> lock(m_mutex); - for (auto & data : m_queue) - data.DestroyGlyph(); - m_queue.clear(); -} - -bool GlyphGenerator::IsSuspended() const -{ - std::lock_guard<std::mutex> lock(m_mutex); - return m_glyphsCounter == 0; -} - -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<std::mutex> lock(m_mutex); - if (!m_completionHandler) - { - for (auto & data : generationData) - data.DestroyGlyph(); - return; - } - - GlyphGenerationDataArray queue; - std::move(generationData.begin(), generationData.end(), std::back_inserter(m_queue)); - std::swap(m_queue, queue); - m_glyphsCounter += queue.size(); - - // Generate glyphs on the separate thread. - auto generateTask = std::make_shared<GenerateGlyphTask>(std::move(queue)); - auto result = DrapeRoutine::Run([this, generateTask]() mutable - { - generateTask->Run(m_sdfScale); - OnTaskFinished(generateTask); - }); - - if (result) - m_activeTasks.Add(generateTask, result); - else - generateTask->DestroyAllGlyphs(); -} - -void GlyphGenerator::OnTaskFinished(std::shared_ptr<GenerateGlyphTask> const & task) -{ - if (task->IsCancelled()) - { - task->DestroyAllGlyphs(); - return; - } - - auto glyphs = task->StealGeneratedGlyphs(); - - std::lock_guard<std::mutex> lock(m_mutex); - ASSERT_GREATER_OR_EQUAL(m_glyphsCounter, glyphs.size(), ()); - m_glyphsCounter -= glyphs.size(); - m_completionHandler(std::move(glyphs)); - - m_activeTasks.Remove(task); -} - -GlyphIndex::GlyphIndex(m2::PointU size, ref_ptr<GlyphManager> mng) +GlyphIndex::GlyphIndex(m2::PointU const & size, ref_ptr<GlyphManager> mng, + ref_ptr<GlyphGenerator> generator) : m_packer(size) , m_mng(mng) - , m_generator(my::make_unique<GlyphGenerator>(mng->GetSdfScale(), - std::bind(&GlyphIndex::OnGlyphGenerationCompletion, this, _1))) + , m_generator(generator) { + ASSERT(m_mng != nullptr, ()); + 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); @@ -212,7 +105,7 @@ GlyphIndex::GlyphIndex(m2::PointU size, ref_ptr<GlyphManager> mng) GlyphIndex::~GlyphIndex() { - m_generator.reset(); + m_generator->UnregisterListener(make_ref(this)); std::lock_guard<std::mutex> lock(m_mutex); for (auto & node : m_pendingNodes) @@ -225,7 +118,7 @@ ref_ptr<Texture::ResourceInfo> GlyphIndex::MapResource(GlyphKey const & key, boo GlyphGenerator::GlyphGenerationData data; auto result = MapResource(key, newResource, data); if (result != nullptr && newResource) - m_generator->GenerateGlyph(data.m_rect, data.m_glyph); + m_generator->GenerateGlyph(make_ref(this), data.m_rect, data.m_glyph); return result; } @@ -251,7 +144,7 @@ std::vector<ref_ptr<Texture::ResourceInfo>> GlyphIndex::MapResources(std::vector } if (!dataArray.empty()) - m_generator->GenerateGlyphs(std::move(dataArray)); + m_generator->GenerateGlyphs(make_ref(this), std::move(dataArray)); return info; } @@ -307,18 +200,13 @@ bool GlyphIndex::CanBeGlyphPacked(uint32_t glyphsCount) const return m_packer.CanBePacked(glyphsCount, baseSize, baseSize); } -bool GlyphIndex::HasAsyncRoutines() const -{ - return !m_generator->IsSuspended(); -} - size_t GlyphIndex::GetPendingNodesCount() { std::lock_guard<std::mutex> lock(m_mutex); return m_pendingNodes.size(); } -void GlyphIndex::OnGlyphGenerationCompletion(GlyphGenerator::GlyphGenerationDataArray && glyphs) +void GlyphIndex::OnCompleteGlyphGeneration(GlyphGenerator::GlyphGenerationDataArray && glyphs) { std::lock_guard<std::mutex> lock(m_mutex); for (auto & g : glyphs) diff --git a/drape/font_texture.hpp b/drape/font_texture.hpp index 2b2ed09d8e..be664ae1f4 100644 --- a/drape/font_texture.hpp +++ b/drape/font_texture.hpp @@ -1,10 +1,9 @@ #pragma once -#include "drape/drape_routine.hpp" #include "drape/dynamic_texture.hpp" +#include "drape/glyph_generator.hpp" #include "drape/glyph_manager.hpp" #include "drape/pointers.hpp" -#include "drape/texture.hpp" #include <atomic> #include <map> @@ -74,74 +73,12 @@ private: GlyphManager::GlyphMetrics m_metrics; }; -class GlyphGenerator +class GlyphIndex : public GlyphGenerator::Listener { public: - struct GlyphGenerationData - { - 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<GlyphGenerationData>; - - class GenerateGlyphTask - { - public: - explicit GenerateGlyphTask(GlyphGenerationDataArray && glyphs) - : m_glyphs(std::move(glyphs)) - , m_isCancelled(false) - {} - void Run(uint32_t sdfScale); - void Cancel() { m_isCancelled = true; } - - GlyphGenerationDataArray && StealGeneratedGlyphs() { return std::move(m_generatedGlyphs); } - bool IsCancelled() const { return m_isCancelled; } - void DestroyAllGlyphs(); - - private: - GlyphGenerationDataArray m_glyphs; - GlyphGenerationDataArray m_generatedGlyphs; - std::atomic<bool> m_isCancelled; - }; - - using CompletionHandler = std::function<void(GlyphGenerationDataArray &&)>; - - 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: - void OnTaskFinished(std::shared_ptr<GenerateGlyphTask> const & task); - - uint32_t m_sdfScale; - CompletionHandler m_completionHandler; - ActiveTasks<GenerateGlyphTask> m_activeTasks; - - GlyphGenerationDataArray m_queue; - size_t m_glyphsCounter = 0; - mutable std::mutex m_mutex; -}; - -class GlyphIndex -{ -public: - GlyphIndex(m2::PointU size, ref_ptr<GlyphManager> mng); - ~GlyphIndex(); + GlyphIndex(m2::PointU const & size, ref_ptr<GlyphManager> mng, + ref_ptr<GlyphGenerator> generator); + ~GlyphIndex() override; // This function can return nullptr. ref_ptr<Texture::ResourceInfo> MapResource(GlyphKey const & key, bool & newResource); @@ -151,8 +88,6 @@ public: bool CanBeGlyphPacked(uint32_t glyphsCount) const; - bool HasAsyncRoutines() const; - uint32_t GetAbsentGlyphsCount(strings::UniString const & text, int fixedHeight) const; // ONLY for unit-tests. DO NOT use this function anywhere else. @@ -161,11 +96,11 @@ public: private: ref_ptr<Texture::ResourceInfo> MapResource(GlyphKey const & key, bool & newResource, GlyphGenerator::GlyphGenerationData & generationData); - void OnGlyphGenerationCompletion(std::vector<GlyphGenerator::GlyphGenerationData> && glyphs); + void OnCompleteGlyphGeneration(GlyphGenerator::GlyphGenerationDataArray && glyphs) override; GlyphPacker m_packer; ref_ptr<GlyphManager> m_mng; - std::unique_ptr<GlyphGenerator> m_generator; + ref_ptr<GlyphGenerator> m_generator; using ResourceMapping = std::map<GlyphKey, GlyphInfo>; using PendingNode = std::pair<m2::RectU, GlyphManager::Glyph>; @@ -181,8 +116,8 @@ class FontTexture : public DynamicTexture<GlyphIndex, GlyphKey, Texture::Glyph> using TBase = DynamicTexture<GlyphIndex, GlyphKey, Texture::Glyph>; public: FontTexture(m2::PointU const & size, ref_ptr<GlyphManager> glyphMng, - ref_ptr<HWTextureAllocator> allocator) - : m_index(size, glyphMng) + ref_ptr<GlyphGenerator> glyphGenerator, ref_ptr<HWTextureAllocator> allocator) + : m_index(size, glyphMng, glyphGenerator) { TBase::TextureParams params{size, TextureFormat::ALPHA, gl_const::GLLinear, true /* m_usePixelBuffer */}; @@ -203,11 +138,6 @@ public: return m_index.CanBeGlyphPacked(newKeysCount); } - bool HasAsyncRoutines() const override - { - return m_index.HasAsyncRoutines(); - } - uint32_t GetAbsentGlyphsCount(strings::UniString const & text, int fixedHeight) const { return m_index.GetAbsentGlyphsCount(text, fixedHeight); diff --git a/drape/glyph_generator.cpp b/drape/glyph_generator.cpp new file mode 100644 index 0000000000..cf19708674 --- /dev/null +++ b/drape/glyph_generator.cpp @@ -0,0 +1,131 @@ +#include "drape/glyph_generator.hpp" + +#include <iterator> + +using namespace std::placeholders; + +namespace dp +{ +GlyphGenerator::GlyphGenerator(uint32_t sdfScale) + : m_sdfScale(sdfScale) +{} + +GlyphGenerator::~GlyphGenerator() +{ + { + std::lock_guard<std::mutex> lock(m_mutex); + m_listeners.clear(); + } + + // Here we have to wait for active tasks completion, + // because they capture 'this' pointer. + m_activeTasks.FinishAll(); + + std::lock_guard<std::mutex> lock(m_mutex); + for (auto & data : m_queue) + data.DestroyGlyph(); +} + +bool GlyphGenerator::IsSuspended() const +{ + std::lock_guard<std::mutex> lock(m_mutex); + return m_glyphsCounter == 0; +} + +void GlyphGenerator::RegisterListener(ref_ptr<GlyphGenerator::Listener> listener) +{ + std::lock_guard<std::mutex> lock(m_mutex); + m_listeners.insert(listener); +} + +void GlyphGenerator::UnregisterListener(ref_ptr<GlyphGenerator::Listener> listener) +{ + std::lock_guard<std::mutex> lock(m_mutex); + m_listeners.erase(listener); +} + +void GlyphGenerator::GenerateGlyph(ref_ptr<Listener> listener, m2::RectU const & rect, + GlyphManager::Glyph & glyph) +{ + GenerateGlyph(listener, GlyphGenerationData(rect, glyph)); +} + +void GlyphGenerator::GenerateGlyph(ref_ptr<Listener> listener, GlyphGenerationData && data) +{ + GenerateGlyphs(listener, {std::move(data)}); +} + +void GlyphGenerator::GenerateGlyphs(ref_ptr<Listener> listener, + GlyphGenerationDataArray && generationData) +{ + std::lock_guard<std::mutex> lock(m_mutex); + if (m_listeners.find(listener) == m_listeners.end()) + { + for (auto & data : generationData) + data.DestroyGlyph(); + return; + } + + GlyphGenerationDataArray queue; + std::move(generationData.begin(), generationData.end(), std::back_inserter(m_queue)); + std::swap(m_queue, queue); + m_glyphsCounter += queue.size(); + + // Generate glyphs on the separate thread. + auto generateTask = std::make_shared<GenerateGlyphTask>(std::move(queue)); + auto result = DrapeRoutine::Run([this, listener, generateTask]() mutable + { + generateTask->Run(m_sdfScale); + OnTaskFinished(listener, generateTask); + }); + + if (result) + m_activeTasks.Add(generateTask, result); + else + generateTask->DestroyAllGlyphs(); +} + +void GlyphGenerator::OnTaskFinished(ref_ptr<Listener> listener, + std::shared_ptr<GenerateGlyphTask> const & task) +{ + if (task->IsCancelled()) + { + task->DestroyAllGlyphs(); + return; + } + + auto glyphs = task->StealGeneratedGlyphs(); + + std::lock_guard<std::mutex> lock(m_mutex); + ASSERT_GREATER_OR_EQUAL(m_glyphsCounter, glyphs.size(), ()); + m_glyphsCounter -= glyphs.size(); + + if (m_listeners.find(listener) != m_listeners.end()) + listener->OnCompleteGlyphGeneration(std::move(glyphs)); + + m_activeTasks.Remove(task); +} + +void GlyphGenerator::GenerateGlyphTask::Run(uint32_t sdfScale) +{ + m_generatedGlyphs.reserve(m_glyphs.size()); + for (auto & data : m_glyphs) + { + if (m_isCancelled) + return; + + auto const g = GlyphManager::GenerateGlyph(data.m_glyph, sdfScale); + data.DestroyGlyph(); + m_generatedGlyphs.emplace_back(GlyphGenerator::GlyphGenerationData{data.m_rect, g}); + } +} + +void GlyphGenerator::GenerateGlyphTask::DestroyAllGlyphs() +{ + for (auto & data : m_glyphs) + data.DestroyGlyph(); + + for (auto & data : m_generatedGlyphs) + data.DestroyGlyph(); +} +} // namespace dp diff --git a/drape/glyph_generator.hpp b/drape/glyph_generator.hpp new file mode 100644 index 0000000000..43380841ce --- /dev/null +++ b/drape/glyph_generator.hpp @@ -0,0 +1,88 @@ +#pragma once + +#include "drape/drape_routine.hpp" +#include "drape/glyph_manager.hpp" +#include "drape/pointers.hpp" + +#include "geometry/rect2d.hpp" + +#include <atomic> +#include <functional> +#include <memory> +#include <mutex> +#include <set> +#include <vector> + +namespace dp +{ +class GlyphGenerator +{ +public: + struct GlyphGenerationData + { + 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<GlyphGenerationData>; + + class Listener + { + public: + virtual ~Listener() = default; + virtual void OnCompleteGlyphGeneration(GlyphGenerationDataArray && glyphs) = 0; + }; + + class GenerateGlyphTask + { + public: + explicit GenerateGlyphTask(GlyphGenerationDataArray && glyphs) + : m_glyphs(std::move(glyphs)) + , m_isCancelled(false) + {} + void Run(uint32_t sdfScale); + void Cancel() { m_isCancelled = true; } + + GlyphGenerationDataArray && StealGeneratedGlyphs() { return std::move(m_generatedGlyphs); } + bool IsCancelled() const { return m_isCancelled; } + void DestroyAllGlyphs(); + + private: + GlyphGenerationDataArray m_glyphs; + GlyphGenerationDataArray m_generatedGlyphs; + std::atomic<bool> m_isCancelled; + }; + + explicit GlyphGenerator(uint32_t sdfScale); + ~GlyphGenerator(); + + void RegisterListener(ref_ptr<Listener> listener); + void UnregisterListener(ref_ptr<Listener> listener); + + void GenerateGlyph(ref_ptr<Listener> listener, m2::RectU const & rect, GlyphManager::Glyph & glyph); + void GenerateGlyph(ref_ptr<Listener> listener, GlyphGenerationData && data); + void GenerateGlyphs(ref_ptr<Listener> listener, GlyphGenerationDataArray && generationData); + bool IsSuspended() const; + +private: + void OnTaskFinished(ref_ptr<Listener> listener, std::shared_ptr<GenerateGlyphTask> const & task); + + uint32_t m_sdfScale; + std::set<ref_ptr<Listener>> m_listeners; + ActiveTasks<GenerateGlyphTask> m_activeTasks; + + GlyphGenerationDataArray m_queue; + size_t m_glyphsCounter = 0; + mutable std::mutex m_mutex; +}; +} // namespace dp diff --git a/drape/texture.hpp b/drape/texture.hpp index d5081f644e..979a251082 100644 --- a/drape/texture.hpp +++ b/drape/texture.hpp @@ -50,7 +50,6 @@ public: virtual ref_ptr<ResourceInfo> FindResource(Key const & key, bool & newResource) = 0; virtual void UpdateState() {} - virtual bool HasAsyncRoutines() const { return false; } virtual bool HasEnoughSpace(uint32_t /*newKeysCount*/) const { return true; } using Params = HWTexture::Params; diff --git a/drape/texture_manager.cpp b/drape/texture_manager.cpp index 9b17445644..a1c7f2ff7a 100644 --- a/drape/texture_manager.cpp +++ b/drape/texture_manager.cpp @@ -136,8 +136,9 @@ m2::PointU ColorTextureSize(size_t colorsCount, uint32_t maxTextureSize) } } // namespace -TextureManager::TextureManager() - : m_maxTextureSize(0) +TextureManager::TextureManager(ref_ptr<GlyphGenerator> glyphGenerator) + : m_glyphGenerator(glyphGenerator) + , m_maxTextureSize(0) , m_maxGlypsCount(0) { m_nothingToUpload.test_and_set(); @@ -275,13 +276,7 @@ void TextureManager::UpdateGlyphTextures() bool TextureManager::HasAsyncRoutines() const { - std::lock_guard<std::mutex> lock(m_glyphTexturesMutex); - for (auto const & texture : m_glyphTextures) - { - if (texture->HasAsyncRoutines()) - return true; - } - return false; + return !m_glyphGenerator->IsSuspended(); } ref_ptr<Texture> TextureManager::AllocateGlyphTexture() @@ -289,6 +284,7 @@ ref_ptr<Texture> TextureManager::AllocateGlyphTexture() std::lock_guard<std::mutex> lock(m_glyphTexturesMutex); m2::PointU size(m_maxTextureSize, m_maxTextureSize); m_glyphTextures.push_back(make_unique_dp<FontTexture>(size, make_ref(m_glyphManager), + m_glyphGenerator, make_ref(m_textureAllocator))); return make_ref(m_glyphTextures.back()); } diff --git a/drape/texture_manager.hpp b/drape/texture_manager.hpp index 57d8ed5e9b..888fa07eae 100644 --- a/drape/texture_manager.hpp +++ b/drape/texture_manager.hpp @@ -1,6 +1,7 @@ #pragma once #include "drape/color.hpp" +#include "drape/glyph_generator.hpp" #include "drape/glyph_manager.hpp" #include "drape/pointers.hpp" #include "drape/texture.hpp" @@ -72,13 +73,13 @@ public: struct Params { std::string m_resPostfix; - double m_visualScale; + double m_visualScale = 1.0; std::string m_colors; std::string m_patterns; GlyphManager::Params m_glyphMngParams; }; - TextureManager(); + explicit TextureManager(ref_ptr<GlyphGenerator> glyphGenerator); void Release(); void Init(Params const & params); @@ -230,6 +231,7 @@ private: static constexpr size_t GetInvalidGlyphGroup(); private: + ref_ptr<GlyphGenerator> m_glyphGenerator; std::string m_resPostfix; std::vector<drape_ptr<Texture>> m_symbolTextures; drape_ptr<Texture> m_stipplePenTexture; |