Browse Source

Textures: Adding a RefCount to textures so backend can avoid destroying them on shutdown if atlas is shared.

ocornut 5 months ago
parent
commit
208705368e
2 changed files with 17 additions and 7 deletions
  1. 14 5
      imgui.cpp
  2. 3 2
      imgui.h

+ 14 - 5
imgui.cpp

@@ -3942,6 +3942,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas)
     Font = NULL;
     FontSize = FontBaseSize = FontScale = CurrentDpiScale = 0.0f;
     IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)();
+    IO.Fonts->RefCount++;
     Time = 0.0f;
     FrameCount = 0;
     FrameCountEnded = FrameCountRendered = -1;
@@ -4212,12 +4213,15 @@ void ImGui::Shutdown()
     IM_ASSERT_USER_ERROR(g.IO.BackendRendererUserData == NULL, "Forgot to shutdown Renderer backend?");
 
     // The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame)
-    if (g.IO.Fonts)
-        ImFontAtlasRemoveDrawListSharedData(g.IO.Fonts, &g.DrawListSharedData);
-    if (g.IO.Fonts && g.FontAtlasOwnedByContext)
+    if (ImFontAtlas* atlas = g.IO.Fonts)
     {
-        g.IO.Fonts->Locked = false;
-        IM_DELETE(g.IO.Fonts);
+        ImFontAtlasRemoveDrawListSharedData(atlas, &g.DrawListSharedData);
+        atlas->RefCount--;
+        if (g.FontAtlasOwnedByContext)
+        {
+            atlas->Locked = false;
+            IM_DELETE(atlas);
+        }
     }
     g.IO.Fonts = NULL;
     g.DrawListSharedData.TempBuffer.clear();
@@ -5192,7 +5196,12 @@ static void ImGui::UpdateTexturesEndFrame()
     g.PlatformIO.Textures.resize(0);
     g.PlatformIO.Textures.reserve(atlas->TexList.Size);
     for (ImTextureData* tex : atlas->TexList)
+    {
+        // We provide this information so backends can decide whether to destroy textures.
+        // This means in practice that if N imgui contexts are created with a shared atlas, we assume all of them have a backend initialized.
+        tex->RefCount = (unsigned short)atlas->RefCount;
         g.PlatformIO.Textures.push_back(tex);
+    }
 }
 
 // Called once a frame. Followed by SetCurrentFont() which sets up the remaining data.

+ 3 - 2
imgui.h

@@ -3379,6 +3379,7 @@ struct IMGUI_API ImTextureData
     ImTextureRect       UpdateRect;             // Bounding box encompassing all individual updates.
     ImVector<ImTextureRect> Updates;            // Array of individual updates.
     int                 UnusedFrames;           // In order to facilitate handling Status==WantDestroy in some backend: this is a count successive frames where the texture was not used. Always >0 when Status==WantDestroy.
+    unsigned short      RefCount;               // Number of contexts using this texture.
     bool                UseColors;              // Tell whether our texture data is known to use colors (rather than just white + alpha).
     bool                WantDestroyNextFrame;   // [Internal] Queued to set ImTextureStatus_WantDestroy next frame. May still be used in the current frame.
 
@@ -3591,13 +3592,12 @@ struct ImFontAtlas
 
     // Input
     ImFontAtlasFlags            Flags;              // Build flags (see ImFontAtlasFlags_)
-    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.
-    int                         TexDesiredWidth;    // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height.
     ImTextureFormat             TexDesiredFormat;   // Desired texture format (default to ImTextureFormat_RGBA32 but may be changed to ImTextureFormat_Alpha8).
     int                         TexGlyphPadding;    // FIXME: Should be called "TexPackPadding". Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0 (will also need to set AntiAliasedLinesUseTex = false).
     void*                       UserData;           // Store your own atlas related user-data (if e.g. you have multiple font atlas).
 
     // [Internal]
+    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<ImTextureData*>    TexList;            // Texture list (most often TexList.Size == 1). TexData is always == TexList.back(). DO NOT USE DIRECTLY, USE GetPlatformIO().Textures[] instead!
     bool                        Locked;             // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert.
@@ -3618,6 +3618,7 @@ struct ImFontAtlas
     const char*                 FontLoaderName;     // Font loader name (for display e.g. in About box) == FontLoader->Name
     void*                       FontLoaderData;     // Font backend opaque storage
     unsigned int                FontBuilderFlags;   // [FIXME: Should be called FontLoaderFlags] Shared flags (for all fonts) for font loader. THIS IS BUILD IMPLEMENTATION DEPENDENT (e.g. . Per-font override is also available in ImFontConfig.
+    int                         RefCount;           // Number of contexts using this atlas
     int                         _PackedSurface;     // Number of packed pixels. Used when compacting to heuristically find the ideal texture size.
     int                         _PackedRects;       // Number of packed rectangles.
     float                       _PackNodesFactor = 1.0f;