From 80404fae3048eb27ae04d06388475ad4b7475deb Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 30 Jan 2025 16:32:25 +0100 Subject: [PATCH] Fonts: clarify ClearTexData() as not supported with dynamic atlases. --- imgui.cpp | 6 ++++-- imgui.h | 4 ++-- imgui_draw.cpp | 42 ++++++++++++++++++++++++------------------ 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index abe3cab3e..0b1433857 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5785,7 +5785,8 @@ void ImGui::EndFrame() UpdateTexturesEndFrame(); // Unlock font atlas - g.IO.Fonts->Locked = false; + ImFontAtlas* atlas = g.IO.Fonts; + atlas->Locked = false; // Clear Input data for next frame g.IO.MousePosPrev = g.IO.MousePos; @@ -8575,8 +8576,9 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) void ImGui::UpdateFontsNewFrame() { ImGuiContext& g = *GImGui; + ImFontAtlas* atlas = g.IO.Fonts; if ((g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0) - g.IO.Fonts->Locked = true; + atlas->Locked = true; SetCurrentFont(GetDefaultFont(), GetDefaultFont()->Sources[0].SizePixels); IM_ASSERT(g.Font->IsLoaded()); } diff --git a/imgui.h b/imgui.h index 85fbb47d9..717c9f0e4 100644 --- a/imgui.h +++ b/imgui.h @@ -3517,7 +3517,7 @@ struct ImFontAtlas // As we are transitioning toward a new font system, we expect to obsolete those soon: IMGUI_API void ClearInputData(); // [OBSOLETE] Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts. IMGUI_API void ClearFonts(); // [OBSOLETE] Clear input+output font data (same as ClearInputData() + glyphs storage, UV coordinates). - IMGUI_API void ClearTexData(); // [OBSOLETE] Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory. + IMGUI_API void ClearTexData(); // [OBSOLETE] Clear CPU-side copy of the texture data. Saves RAM once the texture has been copied to graphics memory. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Legacy path for build atlas + retrieving pixel data. @@ -3592,7 +3592,7 @@ struct ImFontAtlas ImTextureRef TexRef; // User data to refer to the latest texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. ImTextureData* TexData; // Current texture ImVector TexList; // Texture list (most often TexList.Size == 1). TexData is always == TexList.back(). DO NOT USE DIRECTLY, USE GetDrawData().Textures[]/GetPlatformIO().Textures[] instead! - bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. + bool Locked; // Marked as locked during ImGui::NewFrame()..EndFrame() scope if TexUpdates are not supported. Any attempt to modify the atlas will assert. bool RendererHasTextures;// Copy of (BackendFlags & ImGuiBackendFlags_RendererHasTextures) from supporting context. bool TexIsBuilt; // Set when texture was built matching current font input. Mostly useful for legacy IsBuilt() call. bool TexPixelsUseColors; // Tell whether our texture data is known to use colors (rather than just alpha channel), in order to help backend select a format or conversion process. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index e3986229a..7c7a7916a 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2607,9 +2607,11 @@ ImFontAtlas::~ImFontAtlas() void ImFontAtlas::Clear() { - ClearInputData(); - ClearTexData(); ClearFonts(); + bool backup_renderer_has_textures = RendererHasTextures; + RendererHasTextures = false; // Full Clear() is supported, but ClearTexData() only isn't. + ClearTexData(); + RendererHasTextures = backup_renderer_has_textures; } void ImFontAtlas::ClearCache() @@ -2647,12 +2649,14 @@ void ImFontAtlas::ClearInputData() Sources.clear(); } +// Clear CPU-side copy of the texture data. void ImFontAtlas::ClearTexData() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); - TexList.clear(); - IM_DELETE(TexData); - TexData = NULL; + IM_ASSERT(RendererHasTextures == false && "Not supported for dynamic atlases, but you may call Clear()."); + for (ImTextureData* tex : TexList) + tex->DestroyPixels(); + //Locked = true; // Hoped to be able to lock this down but some reload patterns may not be happy with it. } void ImFontAtlas::ClearFonts() @@ -2686,7 +2690,7 @@ static void ImFontAtlasBuildUpdateRendererHasTexturesFromContext(ImFontAtlas* at } // Called by NewFrame(). When multiple context own the atlas, only the first one calls this. -// If you are calling this yourself, ensure atlas->RendererHasTexUpdates is et. +// If you are calling this yourself, ensure atlas->RendererHasTextures is set. // 'frame_count' needs to be provided because we can gc/prioritize baked fonts based on their age. void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count) { @@ -3256,7 +3260,7 @@ bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor curso return true; } -// When atlas->RendererHasTexUpdates == true, this is only called if no font were loaded. +// When atlas->RendererHasTextures = true, this is only called if no font were loaded. void ImFontAtlasBuildMain(ImFontAtlas* atlas) { IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!"); @@ -3481,16 +3485,6 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_ //----------------------------------------------------------------------------------------------------------------------------- -ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size) -{ - struct { ImGuiID FontId; float BakedSize; } hashed_data; - hashed_data.FontId = font_id; - hashed_data.BakedSize = baked_size; - return ImHashData(&hashed_data, sizeof(hashed_data)); -} - -//----------------------------------------------------------------------------------------------------------------------------- - bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) { ImFont* font = src->DstFont; @@ -4910,6 +4904,14 @@ float ImFontBaked::GetCharAdvance(ImWchar c) } IM_MSVC_RUNTIME_CHECKS_RESTORE +ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size) +{ + struct { ImGuiID FontId; float BakedSize; } hashed_data; + hashed_data.FontId = font_id; + hashed_data.BakedSize = baked_size; + return ImHashData(&hashed_data, sizeof(hashed_data)); +} + // ImFontBaked pointers are valid for the entire frame but shall never be kept between frames. ImFontBaked* ImFont::GetFontBaked(float size) { @@ -4920,18 +4922,22 @@ ImFontBaked* ImFont::GetFontBaked(float size) ImFontAtlas* atlas = ContainerAtlas; ImFontAtlasBuilder* builder = atlas->Builder; + // FIXME-BAKED: Design for picking a nearest size? ImGuiID baked_id = ImFontAtlasBakedGetId(FontId, size); ImFontBaked** p_baked_in_map = (ImFontBaked**)builder->BakedMap.GetVoidPtrRef(baked_id); baked = *p_baked_in_map; if (baked != NULL) { - // FIXME-BAKED: Design for picking a nearest size? IM_ASSERT(baked->Size == size && baked->ContainerFont == this && baked->BakedId == baked_id); baked->LastUsedFrame = builder->FrameCount; LastBaked = baked; return baked; } + // FIXME-BAKED: If atlas is locked, find closest match + if (atlas->Locked) + IM_ASSERT(!atlas->Locked && "Cannot use dynamic font size with a locked ImFontAtlas!"); // Locked because rendering backend does not support ImGuiBackendFlags_RendererHasTextures! + // Create new ImGuiContext& g = *GImGui; IM_UNUSED(g); // for IMGUI_DEBUG_LOG_FONT()