From 23a15834fa23226bd26a17f5142b00678617fec4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 29 Jun 2021 17:53:41 +0200 Subject: [PATCH] Fonts: Fix calling ClearTexData() (clearing CPU side font data) triggering an assert in NewFrame(). (#3487) + Backends: added additional assert to facilitate detecting user understand they haven't initialized a backend. --- backends/imgui_impl_allegro5.cpp | 2 ++ backends/imgui_impl_dx10.cpp | 2 ++ backends/imgui_impl_dx11.cpp | 2 ++ backends/imgui_impl_dx12.cpp | 2 ++ backends/imgui_impl_dx9.cpp | 2 ++ backends/imgui_impl_glfw.cpp | 1 + backends/imgui_impl_opengl2.cpp | 2 ++ backends/imgui_impl_opengl3.cpp | 2 ++ backends/imgui_impl_sdl.cpp | 1 + backends/imgui_impl_vulkan.cpp | 3 +++ backends/imgui_impl_win32.cpp | 1 + docs/CHANGELOG.txt | 1 + imgui.h | 3 ++- imgui_draw.cpp | 6 ++++++ 14 files changed, 29 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index ac2fa2d99..96f47f750 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -430,6 +430,8 @@ static void ImGui_ImplAllegro5_UpdateMouseCursor() void ImGui_ImplAllegro5_NewFrame() { ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData(); + IM_ASSERT(bd != NULL && "Did you call ImGui_ImplAllegro5_Init()?"); + if (!bd->Texture) ImGui_ImplAllegro5_CreateDeviceObjects(); diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index 19de96928..9923fb586 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -563,6 +563,8 @@ void ImGui_ImplDX10_Shutdown() void ImGui_ImplDX10_NewFrame() { ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); + IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX10_Init()?"); + if (!bd->pFontSampler) ImGui_ImplDX10_CreateDeviceObjects(); } diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index a5f9f217c..1f074256d 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -579,6 +579,8 @@ void ImGui_ImplDX11_Shutdown() void ImGui_ImplDX11_NewFrame() { ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); + IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX11_Init()?"); + if (!bd->pFontSampler) ImGui_ImplDX11_CreateDeviceObjects(); } diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 079c515c5..1d9810aa8 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -733,6 +733,8 @@ void ImGui_ImplDX12_Shutdown() void ImGui_ImplDX12_NewFrame() { ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); + IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX12_Init()?"); + if (!bd->pPipelineState) ImGui_ImplDX12_CreateDeviceObjects(); } diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index 07c35ea12..fcfab0903 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -362,6 +362,8 @@ void ImGui_ImplDX9_InvalidateDeviceObjects() void ImGui_ImplDX9_NewFrame() { ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); + IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX9_Init()?"); + if (!bd->FontTexture) ImGui_ImplDX9_CreateDeviceObjects(); } diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index cc3c58fc8..c48e33af1 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -384,6 +384,7 @@ void ImGui_ImplGlfw_NewFrame() { ImGuiIO& io = ImGui::GetIO(); ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + IM_ASSERT(bd != NULL && "Did you call ImGui_ImplGlfw_InitForXXX()?"); // Setup display size (every frame to accommodate for window resizing) int w, h; diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index 5a39edfa3..01f2eb548 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -96,6 +96,8 @@ void ImGui_ImplOpenGL2_Shutdown() void ImGui_ImplOpenGL2_NewFrame() { ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); + IM_ASSERT(bd != NULL && "Did you call ImGui_ImplOpenGL2_Init()?"); + if (!bd->FontTexture) ImGui_ImplOpenGL2_CreateDeviceObjects(); } diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 2204b3331..c7ef6432a 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -305,6 +305,8 @@ void ImGui_ImplOpenGL3_Shutdown() void ImGui_ImplOpenGL3_NewFrame() { ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); + IM_ASSERT(bd != NULL && "Did you call ImGui_ImplOpenGL3_Init()?"); + if (!bd->ShaderHandle) ImGui_ImplOpenGL3_CreateDeviceObjects(); } diff --git a/backends/imgui_impl_sdl.cpp b/backends/imgui_impl_sdl.cpp index c7c28e04b..676bb9801 100644 --- a/backends/imgui_impl_sdl.cpp +++ b/backends/imgui_impl_sdl.cpp @@ -381,6 +381,7 @@ void ImGui_ImplSDL2_NewFrame(SDL_Window* window) { ImGuiIO& io = ImGui::GetIO(); ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); + IM_ASSERT(bd != NULL && "Did you call ImGui_ImplSDL2_Init()?"); IM_ASSERT(bd->Window == window); // FIXME: Should remove parameter from ImGui_ImplSDL2_NewFrame() // Setup display size (every frame to accommodate for window resizing) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 5f2a192d8..36d861a59 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -1060,6 +1060,9 @@ void ImGui_ImplVulkan_Shutdown() void ImGui_ImplVulkan_NewFrame() { + ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); + IM_ASSERT(bd != NULL && "Did you call ImGui_ImplVulkan_Init()?"); + IM_UNUSED(bd); } void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count) diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index 09d127083..7e60a5110 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -289,6 +289,7 @@ void ImGui_ImplWin32_NewFrame() { ImGuiIO& io = ImGui::GetIO(); ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); + IM_ASSERT(bd != NULL && "Did you call ImGui_ImplWin32_Init()?"); // Setup display size (every frame to accommodate for window resizing) RECT rect = { 0, 0, 0, 0 }; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index aeb6dd4b2..fb6e0688d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -52,6 +52,7 @@ Other Changes: - Fonts: Prefer using U+FFFD character for fallback instead of '?', if available. (#4269) - Fonts: Use U+FF0E dot character to construct an ellipsis if U+002E '.' is not available. (#4269) - Fonts: Add U+FFFD ("replacement character") to default asian glyphs ranges. (#4269) +- Fonts: Fix calling ClearTexData() (clearing CPU side font data) triggering an assert in NewFrame(). (#3487) - Demo: Fixed requirement in 1.83 to link with imgui_demo.cpp if IMGUI_DISABLE_METRICS_WINDOW is not set. (#4171) Normally the right way to disable compiling the demo is to set IMGUI_DISABLE_DEMO_WINDOWS, but we want to avoid implying that the file is required. diff --git a/imgui.h b/imgui.h index 35cd4c920..c7df32dd3 100644 --- a/imgui.h +++ b/imgui.h @@ -2627,7 +2627,7 @@ struct ImFontAtlas IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel - bool IsBuilt() const { return Fonts.Size > 0 && (TexPixelsAlpha8 != NULL || TexPixelsRGBA32 != NULL); } + bool IsBuilt() const { return Fonts.Size > 0 && TexReady; } // Bit ambiguous: used to detect when user didn't built texture but effectively we should check TexID != 0 except that would be backend dependent... void SetTexID(ImTextureID id) { TexID = id; } //------------------------------------------- @@ -2677,6 +2677,7 @@ struct ImFontAtlas // [Internal] // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you. + bool TexReady; // Set when texture was built matching current font input 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. unsigned char* TexPixelsAlpha8; // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight unsigned int* TexPixelsRGBA32; // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 diff --git a/imgui_draw.cpp b/imgui_draw.cpp index bd99eadf9..f8a3fb08e 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2002,6 +2002,7 @@ void ImFontAtlas::ClearInputData() ConfigData.clear(); CustomRects.clear(); PackIdMouseCursors = PackIdLines = -1; + TexReady = false; } void ImFontAtlas::ClearTexData() @@ -2014,12 +2015,14 @@ void ImFontAtlas::ClearTexData() TexPixelsAlpha8 = NULL; TexPixelsRGBA32 = NULL; TexPixelsUseColors = false; + // Important: we leave TexReady untouched } void ImFontAtlas::ClearFonts() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); Fonts.clear_delete(); + TexReady = false; } void ImFontAtlas::Clear() @@ -2092,6 +2095,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) new_font_cfg.DstFont->EllipsisChar = font_cfg->EllipsisChar; // Invalidate texture + TexReady = false; ClearTexData(); return new_font_cfg.DstFont; } @@ -2795,6 +2799,8 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas) for (int i = 0; i < atlas->Fonts.Size; i++) if (atlas->Fonts[i]->DirtyLookupTables) atlas->Fonts[i]->BuildLookupTable(); + + atlas->TexReady = true; } // Retrieve list of range (2 int per range, values are inclusive)