This page covers the custom draw command system in Dear ImGui, which allows you to inject custom rendering code into the ImGui draw stream using draw callbacks. This includes:
ImDrawList::AddCallback() to insert custom rendering commandsFor information about the basic drawing API and primitives (rectangles, lines, text, etc.), see Draw System and Rendering Pipeline. For texture management, see Texture and Resource Management.
Custom draw commands allow you to execute arbitrary rendering code at specific points in the ImGui draw stream. This is accomplished through draw callbacks - function pointers stored in ImDrawCmd structures that backends invoke during rendering.
Custom Draw Command Flow
Sources: imgui.h2677-2692 imgui_draw.cpp446-468 imgui_draw.cpp523-543 backends/imgui_impl_vulkan.cpp627-670
Every rendering operation in ImGui is encoded as an ImDrawCmd structure. When you add a callback, you're inserting a special ImDrawCmd with a function pointer instead of regular draw data.
| Field | Type | Purpose |
|---|---|---|
UserCallback | ImDrawCallback | Function pointer for custom rendering (NULL for normal draws) |
UserCallbackData | void* | User data passed to the callback |
TexRef | ImTextureRef | Texture to use for this draw command |
ClipRect | ImVec4 | Clipping rectangle |
VtxOffset | unsigned int | Start offset in vertex buffer |
IdxOffset | unsigned int | Start offset in index buffer |
ElemCount | unsigned int | Number of indices to draw |
Sources: imgui.h2859-2889
Use ImDrawList::AddCallback() to insert a callback into the draw stream:
The callback signature is:
Sources: imgui.h2677-2679 imgui_draw.cpp523-543
parent_list: The ImDrawList that generated this command. Use this to access vertex/index buffers and state.cmd: The ImDrawCmd structure containing UserCallbackData and other context.Sources: imgui.h2677-2679
ImGui defines two special callback values that are recognized by all standard backends:
This special callback value ((ImDrawCallback)-1) instructs the backend to reset all render state to ImGui defaults. This is useful when your custom callback has modified render state and you want to ensure it's restored.
This is an internal callback value used by ImGui. User code should not use it.
Sources: imgui.h2681-2692 backends/imgui_impl_vulkan.cpp650-655 backends/imgui_impl_opengl3.cpp390-395
Starting from version 1.92, backends expose selected render state through ImGuiPlatformIO::Renderer_RenderState. This allows callbacks to access backend-specific state like command buffers, render passes, and pipeline state.
Each backend defines its own render state structure accessible through ImGuiPlatformIO::Renderer_RenderState:
Backend Render State Structures
Sources: backends/imgui_impl_vulkan.cpp127-136 backends/imgui_impl_dx11.cpp84-88 backends/imgui_impl_dx12.cpp123-131
All renderer backends follow a similar pattern when processing ImDrawData:
Backend Draw Command Processing Sequence
The OpenGL3 backend processes callbacks in ImGui_ImplOpenGL3_RenderDrawData():
The Vulkan backend processes callbacks in ImGui_ImplVulkan_RenderDrawData():
Sources: backends/imgui_impl_opengl3.cpp377-450 backends/imgui_impl_vulkan.cpp627-700 backends/imgui_impl_dx11.cpp240-290 backends/imgui_impl_dx12.cpp370-440
Modify the clipping rectangle for special rendering needs:
Switch shaders mid-stream for special effects:
Render 3D content within an ImGui window:
Sources: imgui_demo.cpp9584-9650 (Custom Rendering section)
Draw callbacks interact with ImGui's channel splitting system (ImDrawListSplitter). When channels are used to reorder drawing (e.g., in tables or when manually splitting), callbacks are subject to the same channel ordering:
Draw Channels and Callback Ordering
Key Points:
ImDrawListSplitter::Merge() combines all channels in orderImGuiTable) to draw columns out of orderImDrawList::ChannelsSplit() and ChannelsMerge()Sources: imgui_internal.h1018-1044 imgui_draw.cpp1771-1873 imgui_tables.cpp1695-1780
ImDrawCallback_ResetRenderState or manually restore stateBatching Example:
ImDrawList::AddCallback() Internal Flow
AddCallback() Behavior:
_OnChangedClipRect() and _OnChangedTextureID() to ensure any pending primitives are finalized in a separate commandPopUnusedDrawCmd() to remove the previous command if it has ElemCount == 0ImDrawCmd to CmdBufferUserCallback = your function pointerUserCallbackData = your data pointerElemCount = 0 (no vertices/indices to draw)ClipRect, TexRef, and VtxOffset from current stateSources: imgui_draw.cpp523-543 imgui_draw.cpp446-468
Not all backends handle callbacks identically:
ImDrawList and ImDrawCmd are const during callback executionImGui::Text(), ImGui::Button(), etc.)ClipRect in ImDrawCmdSources: imgui.h2681-2692 imgui_draw.cpp523-543
The Dear ImGui demo includes examples of custom rendering:
The demo window has a "Custom Rendering" section that demonstrates:
GetWindowDrawList() and GetBackgroundDrawList()Located at imgui_demo.cpp9584-9650
The demo shows how to create a drawable canvas with custom clipping and mouse interaction.
Sources: imgui_demo.cpp9584-9650
Custom draw commands via ImDrawList::AddCallback() provide a powerful mechanism to:
Key points:
ImGuiPlatformIO::Renderer_RenderStateSources: imgui.h2677-2692 imgui_draw.cpp523-543 backends/imgui_impl_vulkan.cpp127-136 backends/imgui_impl_opengl3.cpp390-403
Refresh this wiki