Fonts: Fallback glyph is now lazily loaded on demand (yay!). Moving ImFontBaked:: functions outside of class.

This commit is contained in:
ocornut
2025-02-10 22:32:09 +01:00
parent 78a17038c2
commit d8a612f73b
2 changed files with 48 additions and 36 deletions

View File

@@ -3652,7 +3652,8 @@ struct ImFontBaked
// [Internal] Members: Cold
float Ascent, Descent; // 4+4 // out // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled)
unsigned int MetricsTotalSurface:26;// 3 // out // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs)
unsigned int WantDestroy:1; // 1 // // Queued for destroy
unsigned int WantDestroy:1; // 0 // // Queued for destroy
unsigned int LockLoadingFallback:1; // 0 // //
int LastUsedFrame; // 4 // // Record of that time this was bounds
ImGuiID BakedId; // 4 //
ImFont* ContainerFont; // 4-8 // in // Parent font
@@ -3665,8 +3666,6 @@ struct ImFontBaked
IMGUI_API ImFontGlyph* FindGlyphNoFallback(ImWchar c); // Return NULL if glyph doesn't exist
IMGUI_API float GetCharAdvance(ImWchar c);
IMGUI_API bool IsGlyphLoaded(ImWchar c);
IMGUI_API ImFontGlyph* BuildLoadGlyph(ImWchar c);
IMGUI_API void BuildGrowIndex(int new_size);
};
// Font flags

View File

@@ -2499,6 +2499,7 @@ void ImTextureData::DestroyPixels()
// - ImFontAtlasBuildAddFont()
// - ImFontAtlasBuildSetupFontBakedEllipsis()
// - ImFontAtlasBuildSetupFontBakedBlanks()
// - ImFontAtlasBuildSetupFontBakedFallback()
// - ImFontAtlasBuildSetupFontSpecialGlyphs()
// - ImFontAtlasBuildDiscardBakes()
// - ImFontAtlasBuildDiscardFontBakedGlyph()
@@ -2527,7 +2528,8 @@ void ImTextureData::DestroyPixels()
// - ImFontAtlasPackAddRect()
// - ImFontAtlasPackGetRect()
//-----------------------------------------------------------------------------
// - ImFont::BuildLoadGlyph()
// - ImFontBaked_BuildGrowIndex()
// - ImFontBaked_BuildLoadGlyph()
// - ImFontAtlasDebugLogTextureRequests()
//-----------------------------------------------------------------------------
// - ImFontAtlasGetFontLoaderForStbTruetype()
@@ -3242,7 +3244,7 @@ int ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float font_size, Im
ImFontAtlasTextureBlockQueueUpload(this, TexData, r->x, r->y, r->w, r->h);
if (baked->IsGlyphLoaded(codepoint))
ImFontAtlasBuildDiscardFontBakedGlyph(this, font, baked, (ImFontGlyph*)(void*)baked->FindGlyph(codepoint));
ImFontAtlasBuildDiscardFontBakedGlyph(this, font, baked, baked->FindGlyph(codepoint));
ImFontGlyph glyph;
glyph.Codepoint = codepoint;
@@ -3367,7 +3369,7 @@ void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas)
IM_ASSERT(ranges != NULL);
for (; ranges[0]; ranges += 2)
for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560
baked->FindGlyphNoFallback((ImWchar)c);
baked->FindGlyph((ImWchar)c);
}
}
@@ -3587,25 +3589,23 @@ static ImFontGlyph* ImFontAtlasBuildSetupFontBakedEllipsis(ImFontAtlas* atlas, I
return glyph;
}
static void ImFontAtlasBuildSetupFontBakedSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked)
// Load fallback in order to obtain its index
// (this is called from in hot-path so we avoid extraneous parameters to minimize impact on code size)
static void ImFontAtlasBuildSetupFontBakedFallback(ImFontBaked* baked)
{
// Mark space as always hidden (not strictly correct/necessary. but some e.g. icons fonts don't have a space. it tends to look neater in previews)
ImFontGlyph* space_glyph = (ImFontGlyph*)(void*)baked->FindGlyphNoFallback((ImWchar)' ');
if (space_glyph != NULL)
space_glyph->Visible = false;
// Load fallback in order to obtain its index
// FIXME-NEWATLAS: could we use a scheme where this is lazily loaded?
IM_ASSERT(baked->FallbackGlyphIndex == -1);
IM_ASSERT(baked->FallbackAdvanceX == 0.0f);
ImFont* font = baked->ContainerFont;
ImFontGlyph* fallback_glyph = NULL;
if (font->FallbackChar != 0)
fallback_glyph = baked->FindGlyphNoFallback(font->FallbackChar);
if (fallback_glyph == NULL)
{
ImFontGlyph* space_glyph = baked->FindGlyphNoFallback((ImWchar)' ');
ImFontGlyph glyph;
glyph.Codepoint = 0;
glyph.AdvanceX = space_glyph ? space_glyph->AdvanceX : IM_ROUND(baked->Size * 0.40f);
fallback_glyph = ImFontAtlasBakedAddFontGlyph(atlas, baked, NULL, &glyph);
fallback_glyph = ImFontAtlasBakedAddFontGlyph(font->ContainerAtlas, baked, NULL, &glyph);
}
baked->FallbackGlyphIndex = baked->Glyphs.index_from_ptr(fallback_glyph); // Storing index avoid need to update pointer on growth and simplify inner loop code
baked->FallbackAdvanceX = fallback_glyph->AdvanceX;
@@ -3711,7 +3711,7 @@ ImFontBaked* ImFontAtlasBuildAddFontBaked(ImFontAtlas* atlas, ImFont* font, floa
loader_data_p += loader->FontBakedSrcLoaderDataSize;
}
ImFontAtlasBuildSetupFontBakedSpecialGlyphs(atlas, baked->ContainerFont, baked);
ImFontAtlasBuildSetupFontBakedBlanks(atlas, baked);
return baked;
}
@@ -4260,13 +4260,26 @@ static bool ImFontAtlasBuildAcceptCodepointForSource(ImFontConfig* src, ImWchar
return true;
}
ImFontGlyph* ImFontBaked::BuildLoadGlyph(ImWchar codepoint)
static void ImFontBaked_BuildGrowIndex(ImFontBaked* baked, int new_size)
{
ImFont* font = ContainerFont;
ImFontBaked* baked = this;
IM_ASSERT(baked->IndexAdvanceX.Size == baked->IndexLookup.Size);
if (new_size <= baked->IndexLookup.Size)
return;
baked->IndexAdvanceX.resize(new_size, -1.0f);
baked->IndexLookup.resize(new_size, IM_FONTGLYPH_INDEX_UNUSED);
}
static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codepoint)
{
ImFont* font = baked->ContainerFont;
ImFontAtlas* atlas = font->ContainerAtlas;
if (atlas->Locked || (font->Flags & ImFontFlags_NoLoadGlyphs))
{
// Lazily load fallback glyph
if (baked->FallbackGlyphIndex == -1 && baked->LockLoadingFallback == 0)
ImFontAtlasBuildSetupFontBakedFallback(baked);
return NULL;
}
//char utf8_buf[5];
//IMGUI_DEBUG_LOG("[font] BuildLoadGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint));
@@ -4293,8 +4306,14 @@ ImFontGlyph* ImFontBaked::BuildLoadGlyph(ImWchar codepoint)
loader_user_data_p += loader->FontBakedSrcLoaderDataSize;
}
// Lazily load fallback glyph
if (baked->LockLoadingFallback)
return NULL;
if (baked->FallbackGlyphIndex == -1)
ImFontAtlasBuildSetupFontBakedFallback(baked);
// Mark index as not found, so we don't attempt the search twice
baked->BuildGrowIndex(codepoint + 1);
ImFontBaked_BuildGrowIndex(baked, codepoint + 1);
baked->IndexAdvanceX[codepoint] = baked->FallbackAdvanceX;
baked->IndexLookup[codepoint] = IM_FONTGLYPH_INDEX_NOT_FOUND;
return NULL;
@@ -4302,10 +4321,10 @@ ImFontGlyph* ImFontBaked::BuildLoadGlyph(ImWchar codepoint)
// The point of this indirection is to not be inlined in debug mode in order to not bloat inner loop.b
IM_MSVC_RUNTIME_CHECKS_OFF
static float BuildLoadGlyphGetAdvanceOrFallback(ImFontBaked* font, unsigned int codepoint)
static float BuildLoadGlyphGetAdvanceOrFallback(ImFontBaked* baked, unsigned int codepoint)
{
ImFontGlyph* glyph = font->BuildLoadGlyph((ImWchar)codepoint);
return glyph ? glyph->AdvanceX : font->FallbackAdvanceX;
ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(baked, (ImWchar)codepoint);
return glyph ? glyph->AdvanceX : baked->FallbackAdvanceX;
}
IM_MSVC_RUNTIME_CHECKS_RESTORE
@@ -4861,15 +4880,6 @@ void ImFontBaked::ClearOutputData()
MetricsTotalSurface = 0;
}
void ImFontBaked::BuildGrowIndex(int new_size)
{
IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size);
if (new_size <= IndexLookup.Size)
return;
IndexAdvanceX.resize(new_size, -1.0f);
IndexLookup.resize(new_size, IM_FONTGLYPH_INDEX_UNUSED);
}
ImFont::ImFont()
{
memset(this, 0, sizeof(*this));
@@ -4950,7 +4960,7 @@ ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked
// Update lookup tables
int codepoint = glyph.Codepoint;
baked->BuildGrowIndex(codepoint + 1);
ImFontBaked_BuildGrowIndex(baked, codepoint + 1);
baked->IndexAdvanceX[codepoint] = glyph.AdvanceX;
baked->IndexLookup[codepoint] = (ImU16)glyph_idx;
const int page_n = codepoint / 8192;
@@ -5002,7 +5012,7 @@ ImFontGlyph* ImFontBaked::FindGlyph(ImWchar c)
if (i != IM_FONTGLYPH_INDEX_UNUSED)
return &Glyphs.Data[i];
}
ImFontGlyph* glyph = BuildLoadGlyph(c);
ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(this, c);
return glyph ? glyph : &Glyphs.Data[FallbackGlyphIndex];
}
@@ -5017,7 +5027,10 @@ ImFontGlyph* ImFontBaked::FindGlyphNoFallback(ImWchar c)
if (i != IM_FONTGLYPH_INDEX_UNUSED)
return &Glyphs.Data[i];
}
return BuildLoadGlyph(c);
LockLoadingFallback = true; // This is actually a rare call, not done in hot-loop, so we prioritize not adding extra cruft to ImFontBaked_BuildLoadGlyph() call sites.
ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(this, c);
LockLoadingFallback = false;
return glyph;
}
bool ImFontBaked::IsGlyphLoaded(ImWchar c)
@@ -5060,7 +5073,7 @@ float ImFontBaked::GetCharAdvance(ImWchar c)
}
// Same as BuildLoadGlyphGetAdvanceOrFallback():
const ImFontGlyph* glyph = BuildLoadGlyph(c);
const ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(this, c);
return glyph ? glyph->AdvanceX : FallbackAdvanceX;
}
IM_MSVC_RUNTIME_CHECKS_RESTORE