diff --git a/scwx-qt/source/scwx/qt/manager/font_manager.cpp b/scwx-qt/source/scwx/qt/manager/font_manager.cpp index 994d5a53..2b38168c 100644 --- a/scwx-qt/source/scwx/qt/manager/font_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/font_manager.cpp @@ -30,16 +30,15 @@ struct FontRecord std::string filename_ {}; }; +typedef std::pair> FontRecordPair; + template struct FontRecordHash; -template -struct FontRecordKeyEqual; - template<> -struct FontRecordHash> +struct FontRecordHash { - size_t operator()(const std::pair& x) const; + size_t operator()(const FontRecordPair& x) const; }; class FontManager::Impl @@ -65,9 +64,9 @@ public: std::shared_mutex imguiFontAtlasMutex_ {}; - boost::unordered_flat_map, + boost::unordered_flat_map, - FontRecordHash>> + FontRecordHash> imguiFonts_ {}; std::shared_mutex imguiFontsMutex_ {}; @@ -88,7 +87,8 @@ std::shared_mutex& FontManager::imgui_font_atlas_mutex() std::shared_ptr FontManager::GetImGuiFont(const std::string& family, const std::vector& styles, - units::font_size::points size) + units::font_size::points size, + bool loadIfNotFound) { const std::string styleString = fmt::format("{}", fmt::join(styles, " ")); const std::string fontString = @@ -100,14 +100,16 @@ FontManager::GetImGuiFont(const std::string& family, // Only allow whole pixels, and clamp to 6-72 pt units::font_size::pixels pixels {size}; - int imFontSize = std::clamp(static_cast(pixels.value()), 8, 96); + units::font_size::pixels imFontSize { + std::clamp(static_cast(pixels.value()), 8, 96)}; + auto imguiFontKey = std::make_pair(fontRecord, imFontSize); // Search for a loaded ImGui font { std::shared_lock imguiFontLock {p->imguiFontsMutex_}; // Search for the associated ImGui font - auto it = p->imguiFonts_.find(std::make_pair(fontRecord, imFontSize)); + auto it = p->imguiFonts_.find(imguiFontKey); if (it != p->imguiFonts_.end()) { return it->second; @@ -116,17 +118,38 @@ FontManager::GetImGuiFont(const std::string& family, // No ImGui font was found, we need to create one } + // No font was found, return an empty shared pointer if not loading + if (!loadIfNotFound) + { + return nullptr; + } + // Get raw font data const auto& rawFontData = p->GetRawFontData(fontRecord.filename_); - // TODO: Create an ImGui font - // TODO: imguiFontLock could be acquired during a render loop, when the font - // atlas is already locked. Lock the font atlas first. Unless it's already - // locked. It might need to be reentrant? - // TODO: Search for font once more, to prevent loading the same font twice - Q_UNUSED(rawFontData); + // The font atlas mutex might already be locked within an ImGui render frame. + // Lock the font atlas mutex before the fonts mutex to prevent deadlock. + std::unique_lock imguiFontAtlasLock {p->imguiFontAtlasMutex_}; + std::unique_lock imguiFontsLock {p->imguiFontsMutex_}; - return nullptr; + // Search for the associated ImGui font again, to prevent loading the same + // font twice + auto it = p->imguiFonts_.find(imguiFontKey); + if (it != p->imguiFonts_.end()) + { + return it->second; + } + + // Create an ImGui font + std::shared_ptr imguiFont = + std::make_shared( + fontRecord.filename_, rawFontData, imFontSize); + + // Store the ImGui font + p->imguiFonts_.insert_or_assign(imguiFontKey, imguiFont); + + // Return the ImGui font + return imguiFont; } const std::vector& @@ -311,14 +334,13 @@ FontManager& FontManager::Instance() return instance_; } -size_t FontRecordHash>::operator()( - const std::pair& x) const +size_t FontRecordHash::operator()(const FontRecordPair& x) const { size_t seed = 0; boost::hash_combine(seed, x.first.family_); boost::hash_combine(seed, x.first.style_); boost::hash_combine(seed, x.first.filename_); - boost::hash_combine(seed, x.second); + boost::hash_combine(seed, x.second.value()); return seed; } diff --git a/scwx-qt/source/scwx/qt/manager/font_manager.hpp b/scwx-qt/source/scwx/qt/manager/font_manager.hpp index c647c31a..171da79c 100644 --- a/scwx-qt/source/scwx/qt/manager/font_manager.hpp +++ b/scwx-qt/source/scwx/qt/manager/font_manager.hpp @@ -26,7 +26,8 @@ public: std::shared_ptr GetImGuiFont(const std::string& family, const std::vector& styles, - units::font_size::points size); + units::font_size::points size, + bool loadIfNotFound = false); void LoadApplicationFont(const std::string& filename); diff --git a/scwx-qt/source/scwx/qt/types/imgui_font.cpp b/scwx-qt/source/scwx/qt/types/imgui_font.cpp index b2b42acd..f7ba126c 100644 --- a/scwx-qt/source/scwx/qt/types/imgui_font.cpp +++ b/scwx-qt/source/scwx/qt/types/imgui_font.cpp @@ -23,9 +23,9 @@ static const auto logger_ = scwx::util::Logger::Create(logPrefix_); class ImGuiFont::Impl { public: - explicit Impl(const std::string& fontName, - const std::string& fontData, - units::pixels size) : + explicit Impl(const std::string& fontName, + const std::vector& fontData, + units::font_size::pixels size) : fontName_ {fontName}, size_ {size} { CreateImGuiFont(fontData); @@ -33,23 +33,23 @@ public: ~Impl() {} - void CreateImGuiFont(const std::string& fontData); + void CreateImGuiFont(const std::vector& fontData); - const std::string fontName_; - const units::pixels size_; + const std::string fontName_; + const units::font_size::pixels size_; ImFont* imFont_ {nullptr}; }; -ImGuiFont::ImGuiFont(const std::string& fontName, - const std::string& fontData, - units::pixels size) : +ImGuiFont::ImGuiFont(const std::string& fontName, + const std::vector& fontData, + units::font_size::pixels size) : p(std::make_unique(fontName, fontData, size)) { } ImGuiFont::~ImGuiFont() = default; -void ImGuiFont::Impl::CreateImGuiFont(const std::string& fontData) +void ImGuiFont::Impl::CreateImGuiFont(const std::vector& fontData) { logger_->debug("Creating Font: {}", fontName_); @@ -66,7 +66,7 @@ void ImGuiFont::Impl::CreateImGuiFont(const std::string& fontData) fontConfig.Name[sizeof(fontConfig.Name) - 1] = 0; imFont_ = fontAtlas->AddFontFromMemoryTTF( - const_cast(static_cast(fontData.c_str())), + const_cast(static_cast(fontData.data())), static_cast(std::clamp( fontData.size(), 0, std::numeric_limits::max())), sizePixels, diff --git a/scwx-qt/source/scwx/qt/types/imgui_font.hpp b/scwx-qt/source/scwx/qt/types/imgui_font.hpp index 8c07cd95..9a69ac6e 100644 --- a/scwx-qt/source/scwx/qt/types/imgui_font.hpp +++ b/scwx-qt/source/scwx/qt/types/imgui_font.hpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -17,9 +18,9 @@ namespace types class ImGuiFont { public: - explicit ImGuiFont(const std::string& fontName, - const std::string& fontData, - units::pixels size); + explicit ImGuiFont(const std::string& fontName, + const std::vector& fontData, + units::font_size::pixels size); ~ImGuiFont(); ImGuiFont(const ImGuiFont&) = delete;