From 426fdfb27a501fa6d93265b3bf7da59cd47c44da Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Fri, 14 Oct 2022 19:02:46 +0200 Subject: [PATCH] Cache only last 32 font preview. Prevent creation of huge texture for font previews Add reservation of space for no texture(prevent change of comgo box width) --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 92 +++++++++++++++---------- src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp | 15 +++- 2 files changed, 68 insertions(+), 39 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 66be8d68ae..aa6273b263 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -1222,8 +1222,6 @@ void GLGizmoEmboss::draw_text_input() } } -//#define DEBUG_NOT_LOADABLE_FONTS - /// /// Keep list of loadable OS fonts /// Filtrate which can be loaded. @@ -1232,14 +1230,20 @@ void GLGizmoEmboss::draw_text_input() class MyFontEnumerator : public wxFontEnumerator { wxFontEncoding m_encoding; -public: + bool m_fixed_width_only = false; std::vector m_facenames; + std::vector m_facenames_bad; +public: MyFontEnumerator(wxFontEncoding encoding) : m_encoding(encoding) {} + void enumerate() { + m_facenames.clear(); + m_facenames_bad.clear(); + EnumerateFacenames(m_encoding, m_fixed_width_only); + std::sort(m_facenames.begin(), m_facenames.end()); + } -#ifdef DEBUG_NOT_LOADABLE_FONTS - std::vector m_efacenames; -#endif // DEBUG_NOT_LOADABLE_FONTS - + const std::vector &get_face_names() const { return m_facenames; } + const std::vector &get_bad_face_names() const { return m_facenames_bad; } protected: /// /// Called by wxFontEnumerator::EnumerateFacenames() for each match. @@ -1255,9 +1259,7 @@ protected: // Faster chech if wx_font is loadable but not 100% // names could contain not loadable font if (!WxFontUtils::can_load(wx_font)) { -#ifdef DEBUG_NOT_LOADABLE_FONTS - m_efacenames.emplace_back(facename.c_str()); -#endif // DEBUG_NOT_LOADABLE_FONTS + m_facenames_bad.emplace_back(facename); return true; // can't load } /*/ @@ -1265,9 +1267,7 @@ protected: // After this all files are loadable auto font_file = WxFontUtils::create_font_file(wx_font); if (font_file == nullptr) { -#ifdef DEBUG_NOT_LOADABLE_FONTS - m_efacenames.emplace_back(facename.c_str()); -#endif // DEBUG_NOT_LOADABLE_FONTS + m_facenames_bad.emplace_back(facename.c_str()); return true; // can't create font file } // */ m_facenames.push_back(facename); @@ -1289,28 +1289,33 @@ bool GLGizmoEmboss::select_facename(const wxString &facename) { return true; } +static std::string concat(std::vector data) { + std::stringstream ss; + for (const auto &d : data) + ss << d.c_str() << ", "; + return ss.str(); +} + void GLGizmoEmboss::init_face_names() { if (m_face_names.is_init) return; m_face_names.is_init = true; - wxFontEncoding encoding = wxFontEncoding::wxFONTENCODING_SYSTEM; - MyFontEnumerator fontEnumerator(encoding); - bool fixed_width_only = false; + MyFontEnumerator font_enumerator(m_face_names.encoding); { using namespace std::chrono; steady_clock::time_point enumerate_start = steady_clock::now(); - ScopeGuard sg([&enumerate_start]() { + ScopeGuard sg([&enumerate_start, &font_enumerator]() { steady_clock::time_point enumerate_end = steady_clock::now(); long long enumerate_duration = duration_cast(enumerate_end - enumerate_start).count(); - BOOST_LOG_TRIVIAL(info) << "OS Fonts Enumeration " << enumerate_duration << "ms"; + BOOST_LOG_TRIVIAL(info) << "OS enumerate " << font_enumerator.get_face_names().size() << " fonts " + << "(+ " << font_enumerator.get_bad_face_names().size() << " can't load " + << "= " << font_enumerator.get_face_names().size() + font_enumerator.get_bad_face_names().size() << " fonts) " + << "in " << enumerate_duration << " ms\n" << concat(font_enumerator.get_bad_face_names()); }); - fontEnumerator.EnumerateFacenames(encoding, fixed_width_only); + font_enumerator.enumerate(); }// End Time measures - m_face_names.encoding = encoding; - std::vector &names = fontEnumerator.m_facenames; - std::sort(names.begin(), names.end()); - + const std::vector &names = font_enumerator.get_face_names(); const float &width = m_gui_cfg->face_name_max_width; m_face_names.faces.reserve(names.size()); for (const wxString &name : names) { @@ -1333,7 +1338,7 @@ void GLGizmoEmboss::init_font_name_texture() { glsafe(::glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); glsafe(::glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); const Vec2i &size = m_gui_cfg->face_name_size; - GLint w = size.x(), h = m_face_names.faces.size() * size.y(); + GLint w = size.x(), h = m_face_names.count_cached_textures * size.y(); std::vector data(4*w * h, {0}); const GLenum format = GL_RGBA, type = GL_UNSIGNED_BYTE; const GLint level = 0, internal_format = GL_RGBA, border = 0; @@ -1379,7 +1384,6 @@ void GLGizmoEmboss::draw_font_list() if (ImGui::BeginCombo("##font_selector", selected)) { if (!m_face_names.is_init) init_face_names(); if (m_face_names.texture_id == 0) init_font_name_texture(); - ImTextureID tex_id = (void *) (intptr_t) m_face_names.texture_id; unsigned int &count_opened_fonts = m_face_names.count_opened_font_files; for (FaceName &face : m_face_names.faces) { const wxString &face_name = face.name; @@ -1398,17 +1402,18 @@ void GLGizmoEmboss::draw_font_list() ImGui::SetTooltip("%s", face_name.ToUTF8().data()); if (is_selected) ImGui::SetItemDefaultFocus(); + ImVec2 size(m_gui_cfg->face_name_size.x(), m_gui_cfg->face_name_size.y()); + // set to pixel 0,0 in texture + ImVec2 uv0(0.f, 0.f), uv1(1.f, 1.f / size.y / m_face_names.count_cached_textures); + ImTextureID tex_id = (void *) (intptr_t) m_face_names.texture_id; if (face.is_created != nullptr){ - if (*face.is_created){ - ImGui::SameLine(m_gui_cfg->face_name_max_width); - ImVec2 size(m_gui_cfg->face_name_size.x(), - m_gui_cfg->face_name_size.y()), - uv0(0.f, index / (float) m_face_names.faces.size()), - uv1(1.f, (index + 1) / (float) m_face_names.faces.size()); - ImGui::Image(tex_id, size, uv0, uv1); - } else if (!ImGui::IsItemVisible()) { - face.cancel->store(true); + if (*face.is_created) { + size_t texture_index = face.texture_index; + uv0 = ImVec2(0.f, texture_index / (float) m_face_names.count_cached_textures), + uv1 = ImVec2(1.f, (texture_index + 1) / (float) m_face_names.count_cached_textures); + } else if (!ImGui::IsItemVisible()) { face.is_created = nullptr; + face.cancel->store(true); } } else if (ImGui::IsItemVisible() && count_opened_fonts < m_gui_cfg->max_count_opened_font_files) { @@ -1422,12 +1427,25 @@ void GLGizmoEmboss::draw_font_list() // format type and level must match to texture data const GLenum format = GL_RGBA, type = GL_UNSIGNED_BYTE; const GLint level = 0; + // select next texture index + size_t texture_index = (m_face_names.texture_index+1) % m_face_names.count_cached_textures; + // set previous cach as deleted + for (FaceName &f : m_face_names.faces) + if (f.texture_index == texture_index) { + if (f.cancel != nullptr) + f.cancel->store(true); + f.is_created = nullptr; + } + + m_face_names.texture_index = texture_index; + face.texture_index = texture_index; + // render text to texture FontImageData data{text, face_name, m_face_names.encoding, m_face_names.texture_id, - index, + m_face_names.texture_index, m_gui_cfg->face_name_size, gray_level, format, @@ -1441,7 +1459,9 @@ void GLGizmoEmboss::draw_font_list() auto& worker = wxGetApp().plater()->get_ui_job_worker(); queue_job(worker, std::move(job)); } - + + ImGui::SameLine(m_gui_cfg->face_name_texture_offset_x); + ImGui::Image(tex_id, size, uv0, uv1); ImGui::PopID(); } #ifdef SHOW_FONT_COUNT diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index d596d02eaa..bda137d962 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp @@ -191,6 +191,7 @@ private: // maximal size of face name image Vec2i face_name_size = Vec2i(100, 0); float face_name_max_width = 100.f; + float face_name_texture_offset_x = 105.f; // maximal texture generate jobs running at once unsigned int max_count_opened_font_files = 10; @@ -228,7 +229,7 @@ private: struct FaceName{ wxString name; std::string name_truncated = ""; - + size_t texture_index = 0; // State for generation of texture // when start generate create share pointers std::shared_ptr> cancel = nullptr; @@ -242,8 +243,7 @@ private: // flag if face names was enumerated from OS bool is_init = false; - wxFontEncoding encoding; - std::vector faces; + std::vector faces = {}; // Identify if preview texture exists GLuint texture_id = 0; @@ -251,6 +251,15 @@ private: // protection for open too much font files together // Gtk:ERROR:../../../../gtk/gtkiconhelper.c:494:ensure_surface_for_gicon: assertion failed (error == NULL): Failed to load /usr/share/icons/Yaru/48x48/status/image-missing.png: Error opening file /usr/share/icons/Yaru/48x48/status/image-missing.png: Too many open files (g-io-error-quark, 31) unsigned int count_opened_font_files = 0; + + // Configuration of font encoding + const wxFontEncoding encoding = wxFontEncoding::wxFONTENCODING_SYSTEM; + + // Configuration for texture height + const int count_cached_textures = 32; + + // index for new generated texture index(must be lower than count_cached_textures) + size_t texture_index = 0; } m_face_names; // Text to emboss