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)
This commit is contained in:
Filip Sykala - NTB T15p 2022-10-14 19:02:46 +02:00
parent 436384cf65
commit 426fdfb27a
2 changed files with 68 additions and 39 deletions

View file

@ -1222,8 +1222,6 @@ void GLGizmoEmboss::draw_text_input()
}
}
//#define DEBUG_NOT_LOADABLE_FONTS
/// <summary>
/// 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<wxString> m_facenames;
std::vector<wxString> 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<std::string> m_efacenames;
#endif // DEBUG_NOT_LOADABLE_FONTS
const std::vector<wxString> &get_face_names() const { return m_facenames; }
const std::vector<wxString> &get_bad_face_names() const { return m_facenames_bad; }
protected:
/// <summary>
/// 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<wxString> 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<milliseconds>(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<wxString> &names = fontEnumerator.m_facenames;
std::sort(names.begin(), names.end());
const std::vector<wxString> &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<unsigned char> 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

View file

@ -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<std::atomic<bool>> cancel = nullptr;
@ -242,8 +243,7 @@ private:
// flag if face names was enumerated from OS
bool is_init = false;
wxFontEncoding encoding;
std::vector<FaceName> faces;
std::vector<FaceName> 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