From 82eab11a88ce0cc150ea3f98221c3027a0800a71 Mon Sep 17 00:00:00 2001 From: Matija Kecman Date: Sun, 26 Apr 2026 05:18:54 -0700 Subject: [PATCH] Remove deprecated Fonts->Build() and clean up ImGui texture lifecycle * Remove the explicit io.Fonts->Build() call from InitImGui, which was deprecated in Dear ImGui v1.92.0. With ImGuiBackendFlags_RendererHasTextures already set, the font atlas is now built lazily by ImGui and communicated to backends via the ImTextureStatus_WantCreate protocol. * Add proper texture shutdown in ~ImguiBridge by iterating ImGui::GetPlatformIO().Textures and destroying all tracked textures, per the //third_party/dear_imgui/docs/BACKENDS.md instructions. * Remove the "OK but missing" and "WantUpdates but missing" texture recovery hacks from Update(). These handled a state where ImGui thought textures were alive but the Filament-side storage had been torn down. With proper destruction acknowledgement (SetStatus(Destroyed) + SetTexID(Invalid)), ImGui will now transition destroyed textures to WantCreate on the next frame, and the normal creation path handles it cleanly. PiperOrigin-RevId: 905886622 Change-Id: Ic449eeaf083740a67eae9c637fb53546a6192b28 --- .../filament/compat/imgui_bridge.cc | 34 +++++++++---------- src/experimental/platform/hal/window.cc | 12 ++----- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/src/experimental/filament/compat/imgui_bridge.cc b/src/experimental/filament/compat/imgui_bridge.cc index 8b43a3a4..de21a303 100644 --- a/src/experimental/filament/compat/imgui_bridge.cc +++ b/src/experimental/filament/compat/imgui_bridge.cc @@ -26,8 +26,8 @@ #include #include "experimental/filament/filament/material.h" #include "experimental/filament/filament/mesh.h" -#include "experimental/filament/filament/renderable.h" #include "experimental/filament/filament/object_manager.h" +#include "experimental/filament/filament/renderable.h" #include "experimental/filament/filament/scene_view.h" #include "experimental/filament/filament/texture.h" @@ -36,15 +36,25 @@ namespace mujoco { using filament::math::float3; using filament::math::mat3f; -ImguiBridge::ImguiBridge(ObjectManager* object_mgr) - : object_mgr_(object_mgr) { +ImguiBridge::ImguiBridge(ObjectManager* object_mgr) : object_mgr_(object_mgr) { scene_view_ = std::make_unique(object_mgr_->GetEngine()); scene_view_->DisableShadows(); scene_view_->DisableReflections(); scene_view_->DisablePostProcessing(); } -ImguiBridge::~ImguiBridge() { PrepareRenderables(0); } +ImguiBridge::~ImguiBridge() { + PrepareRenderables(0); + + // Destroy all textures tracked by ImGui. + if (ImGui::GetCurrentContext()) { + for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) { + if (tex->Status != ImTextureStatus_Destroyed) { + DestroyTexture(tex); + } + } + } +} uintptr_t ImguiBridge::UploadImage(uintptr_t tex_id, const uint8_t* pixels, int width, int height, int bpp) { @@ -183,22 +193,10 @@ void ImguiBridge::Update() { if (commands->Textures != nullptr) { for (ImTextureData* tex : *commands->Textures) { - if (tex->Status == ImTextureStatus_OK) { - // ImGui's lifecycle is independent of the filament context lifecycle. - // As such, it is possible to destroy and create a new filament context - // while ImGui is still expecting the "OK" textures to work. In this - // case, we simply recreate the texture. - if (textures_.find(tex->TexID) == textures_.end()) { - CreateTexture(tex); - } - } else if (tex->Status == ImTextureStatus_WantCreate) { + if (tex->Status == ImTextureStatus_WantCreate) { CreateTexture(tex); } else if (tex->Status == ImTextureStatus_WantUpdates) { - if (textures_.find(tex->TexID) == textures_.end()) { - CreateTexture(tex); - } else { - UpdateTexture(tex); - } + UpdateTexture(tex); } else if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0) { DestroyTexture(tex); diff --git a/src/experimental/platform/hal/window.cc b/src/experimental/platform/hal/window.cc index 84941444..961e9ab9 100644 --- a/src/experimental/platform/hal/window.cc +++ b/src/experimental/platform/hal/window.cc @@ -47,8 +47,8 @@ extern void* GetNativeWindowOsx(void* window); namespace mujoco::platform { -static void InitImGui(SDL_Window* window, float content_scale, bool load_fonts, - bool build_fonts) { +static void InitImGui(SDL_Window* window, float content_scale, + bool load_fonts) { ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); @@ -85,10 +85,6 @@ static void InitImGui(SDL_Window* window, float content_scale, bool load_fonts, constexpr ImWchar icon_ranges[] = {0xf000, 0xf3ff, 0x000}; io.Fonts->AddFontFromMemoryTTF(data, size, 14.f, &icon_cfg, icon_ranges); - if (build_fonts) { - io.Fonts->Build(); - } - // Note: we purposefully do not "close" the font resources as ImGui may // need them again to resize fonts. } @@ -133,9 +129,7 @@ Window::Window(std::string_view title, int width, int height, Config config) mju_error("Error creating window: %s", SDL_GetError()); } - InitImGui(sdl_window_, content_scale, config.load_fonts, - (config_.gfx_mode != GraphicsMode::ClassicOpenGl && - config_.gfx_mode != GraphicsMode::ClassicOpenGlHeadless)); + InitImGui(sdl_window_, content_scale, config.load_fonts); // Filament (except WebGL) manages its own swap chain including when to swap. // In all other cases, we'll use SDL to manage the swap chain.