This document covers performance optimization techniques and considerations for Dear ImGui applications. It explains how the immediate-mode architecture affects performance, identifies common bottlenecks, and provides practical optimization strategies at the widget, rendering, and system levels.
For integration and backend setup, see Getting Started. For rendering architecture details, see Draw System and Rendering Pipeline. For font-specific optimizations, see Font System.
Dear ImGui is designed with performance as a core principle. The immediate-mode paradigm requires UI to be regenerated every frame, so the library is architected to minimize overhead:
Sources: imgui.cpp220-224
Understanding where time is spent during a frame helps identify optimization opportunities:
Frame Execution Flow with Key Functions
CPU Cost Distribution (typical application):
Key Functions to Profile:
ImGui::NewFrame() - Input processing and per-frame setupImGui::Begin() / ImGui::End() - Window managementButtonBehavior() / InputTextEx() - Widget interaction logicImDrawList::AddRect() / AddText() - Draw command generationImGui::Render() / ImGui::EndFrame() - FinalizationRenderDrawData() - GPU submissionSources: imgui.cpp5270-5388 imgui.cpp5432-5511 imgui_internal.h3397-3450
Use ImGui::ShowMetricsWindow() to display real-time performance metrics:
The metrics window shows:
Sources: imgui.cpp98-101 imgui_demo.cpp408
Sources: imgui.h2491-2563
Dear ImGui integrates well with standard profilers:
Key functions to profile:
ImGui::NewFrame()ImGui::Render()RenderDrawData() implementationSources: imgui.cpp5270-5388
When a window is collapsed, minimized, or fully clipped, window->SkipItems is set to true, causing widgets to early-exit with minimal overhead:
SkipItems Flow in Begin() and Widgets
Implementation Pattern (from actual widgets):
Performance Impact:
Sources: imgui.cpp6809-6865 imgui_widgets.cpp161-163 imgui_widgets.cpp554-669
TextEx() implements automatic coarse clipping for long text content to avoid processing text outside the visible viewport:
Long Text Clipping Logic
Implementation Details (from TextEx()):
Performance Impact:
memchr() for fast newline scanningCalcTextSize() for visible linesNote: Flag ImGuiTextFlags_NoWidthForLargeClippedText can skip width calculation for clipped lines, saving additional time.
Sources: imgui_widgets.cpp160-266
Dear ImGui automatically batches primitives into minimal draw calls. Draw commands are only split when necessary:
Minimize draw calls by:
ImGui::PushClipRect() when not neededSources: imgui_draw.cpp504-665 imgui.h3018-3044
Dear ImGui generates indexed triangle lists with shared vertices:
| Primitive Type | Vertices | Indices | Efficiency |
|---|---|---|---|
| Rectangle (filled) | 4 | 6 | Optimal |
| Rectangle (outline) | 8 | 24 | Good |
| Circle/Arc | N+2 | 3*N | Variable |
| Text character | 4 | 6 | Optimal |
Optimization tips:
ImGui::GetStyle().CircleTessellationMaxErrorSources: imgui_draw.cpp1275-1540
Dear ImGui aims for zero malloc/free in idle frames by pre-allocating and reusing memory pools:
Memory Pools and Allocation Patterns
Key Data Structures and Allocation Patterns:
| Structure | Location | Allocation Pattern | Lifecycle |
|---|---|---|---|
ImGuiContext | GImGui global | Once at CreateContext() | Until DestroyContext() |
ImGuiWindow | g.Windows[] | Once per window name, pooled | Persists across frames |
ImDrawList | window->DrawList | One per window | Persists, buffers grow |
ImDrawCmd | drawlist->CmdBuffer | Reused vector capacity | Cleared per frame |
ImDrawVert | drawlist->VtxBuffer | Grows, keeps capacity | Cleared per frame |
ImGuiTable | g.Tables pool | Pooled by ID via ImPool<> | Reused across frames |
ImGuiStorage | window->StateStorage | Grows as needed | Persists |
ImGuiWindowTempData | window->DC | Stack member | Per-frame state |
ImGuiTableTempData | g.TablesTempData[] | Temporary vector | Stacked per nested table |
Critical Functions for Memory Management:
Memory Allocation Locations:
Startup Phase (CreateContext):
ImGuiContext allocationg.Windows vector capacityFirst Frame (NewFrame → Render):
ImGuiWindow allocatedVtxBuffer/IdxBuffer growImGuiTable allocated from poolSteady State (Subsequent Frames):
Shutdown (DestroyContext):
Monitoring Memory Usage:
Sources: imgui.cpp4131-4153 imgui_internal.h2252-2387 imgui_internal.h2813-2989 imgui_draw.cpp446-458
Sources: imgui.h2096-2166
For lists with thousands of items, ImGuiListClipper automatically calculates which items are visible and skips rendering the rest:
ImGuiListClipper Usage Pattern
Performance Impact by List Size
| Total Items | Without Clipper | With Clipper | Speedup |
|---|---|---|---|
| 100 items | 0.5 ms | 0.15 ms | 3x |
| 1,000 items | 5 ms | 0.15 ms | 33x |
| 10,000 items | 50 ms | 0.15 ms | 333x |
| 100,000 items | 500 ms | 0.15 ms | 3333x |
Assumes ~20 items visible on screen
ImGuiListClipper Internal Flow
Advanced Usage
Table Integration
Key Clipper Members:
DisplayStart / DisplayEnd - Range of visible items to renderItemsCount - Total number of itemsItemsHeight - Calculated height per itemStartPosY / StartSeekOffsetY - Internal seek position trackingRequirements and Limitations:
IncludeItemsByIndex() to force-include specific itemsStep() call measures the first item to determine heightBeginTable() / TableNextRow() automaticallyColumns() (legacy API)Sources: imgui.h2393-2446 imgui.cpp8962-9123 imgui_demo.cpp2740-2850
Frozen columns and rows have minimal overhead:
Automatic optimizations:
ImGuiListClipper for row clippingSources: imgui_tables.cpp49-71 imgui_tables.cpp743-877
Disable unused columns:
Sources: imgui_tables.cpp1066-1179
The dynamic font system (when backend supports ImGuiBackendFlags_RendererHasTextures) provides:
Performance characteristics:
Sources: imgui_draw.cpp16-23 imgui.h35
| Text Length | Typical Frame Cost | Optimization |
|---|---|---|
| < 100 chars | < 0.01 ms | None needed |
| 100-1000 chars | 0.01-0.1 ms | Consider clipping |
| 1000-10000 chars | 0.1-1 ms | Use clipper or manual clipping |
| > 10000 chars | > 1 ms | Use InputTextMultiline with ImGuiInputTextFlags_ReadOnly |
Pre-v1.92 (or without modern backend):
V1.92+ with modern backend:
Sources: imgui_draw.cpp2686-2949 docs/FONTS.md74-85
Problem: Expensive logic executes even when window is collapsed or invisible.
Impact: Can waste 1-10ms per frame for expensive UI logic in collapsed windows.
Sources: imgui.cpp6809-6865 imgui.h652-657
Problem: Allocating memory every frame causes performance spikes and fragmentation.
Sources: imgui.cpp220-224
Problem: Repeated string operations cause O(N²) reallocations.
Impact: 1000 lines can go from 50ms to 0.5ms with proper buffering.
Sources: imgui.h2167-2180
Problem: Creating/destroying GPU textures every frame is extremely expensive.
Impact: Texture creation can cost 10-100ms depending on size and API. Caching provides 100-1000x speedup.
Sources: imgui.h1068-1083
Problem: Rendering thousands of items even when only 20 are visible.
Sources: imgui.h2393-2446 imgui.cpp8962-9123
Problem: ID stack operations add overhead when called thousands of times unnecessarily.
Sources: imgui.cpp8514-8576
| Anti-Pattern | Cost | Fix | Speedup |
|---|---|---|---|
Ignoring Begin() return | 1-10 ms | Check return value | 10-100x |
| Per-frame allocations | 0.1-1 ms | Use static variables | 10-100x |
| String concatenation in loops | 10-50 ms | Use ImGuiTextBuffer | 100x |
| Per-frame texture creation | 10-100 ms | Cache textures | 100-1000x |
| Not using clipper for large lists | 10-500 ms | Use ImGuiListClipper | 100-1000x |
Excessive PushID for non-interactive | 0.5-2 ms | Only ID interactive widgets | 2-5x |
Key sections:
| Section | Information | Optimization Use |
|---|---|---|
| Dear ImGui | Frame rate, active windows | Overall health check |
| Windows | Individual window stats | Find heavy windows |
| DrawLists | Vertices, indices, commands | Identify draw call issues |
| Memory | Allocations, pool sizes | Memory leak detection |
| Viewports | Multi-viewport stats | Platform window overhead |
Adjust visual settings that affect performance:
CircleTessellationMaxError: Higher = fewer verticesCurveTessellationTol: Higher = fewer verticesAntiAlias* flags: Disable for performance gainSources: imgui_demo.cpp408-409
Sources: imgui.cpp13098-13201
High DPI rendering increases vertex counts proportionally:
Sources: imgui.h2521-2528 docs/FAQ.md90-93
Additional considerations for mobile:
Selectable instead of Button with complex content)Sources: imgui_internal.h267
Sources: Multiple sections above
Typical performance targets (desktop, 60 FPS):
| Component | Budget | Notes |
|---|---|---|
| Dear ImGui total | < 2-3 ms | Including draw generation |
| Widget submission | < 1-2 ms | Application code + ImGui logic |
| Draw command generation | < 0.5 ms | ImDrawList operations |
| Backend rendering | < 0.5 ms | GPU upload + draw calls |
When to optimize:
What usually works:
ImGuiListClipper for lists > 100 itemsBegin() return valuesWhat rarely helps:
Sources: imgui.cpp220-224 imgui_demo.cpp9700-9800
Refresh this wiki