This page provides a guide for implementing custom platform and renderer backends for Dear ImGui. It covers the required and optional functions, data structures, and integration patterns needed to create backends for new platforms or rendering APIs not already supported by the standard backends.
Related pages: For an overview of the backend architecture and how backends work, see Backend Architecture Overview. For examples of existing platform backends, see Platform Backends. For examples of existing renderer backends, see Renderer Backends.
You need to write a custom backend when:
Important: Before writing a custom backend, check if your use case can be covered by existing backends. The standard backends in backends/ cover most common scenarios and are well-tested.
Sources: docs/BACKENDS.md12-16 docs/BACKENDS.md193-243
Dear ImGui uses a two-backend architecture that separates platform concerns (input/windowing) from rendering concerns (GPU):
Backend Architecture: Function Call Flow
Platform Backend responsibilities:
Init(), Shutdown(), NewFrame(), ProcessEvent() functionsImGuiIO::BackendPlatformUserDataio.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddKeyEvent(), etc.io.DisplaySize, io.DeltaTime, io.DisplayFramebufferScaleImGuiBackendFlags_HasMouseCursors, ImGuiBackendFlags_HasSetMousePos, ImGuiBackendFlags_HasGamepadRenderer Backend responsibilities:
Init(), Shutdown(), NewFrame(), RenderDrawData() functionsImGuiIO::BackendRendererUserDataImDrawData by iterating through CmdLists[] and issuing draw callsImGuiBackendFlags_RendererHasVtxOffset, ImGuiBackendFlags_RendererHasTexturesSources: docs/BACKENDS.md25-42 backends/imgui_impl_glfw.cpp512-606 backends/imgui_impl_vulkan.cpp1146-1253
All backends follow a consistent pattern for storing backend-specific data using the BackendPlatformUserData or BackendRendererUserData fields:
Example from GLFW backend:
This pattern allows:
Sources: backends/imgui_impl_glfw.cpp188-236 backends/imgui_impl_vulkan.cpp398-404 backends/imgui_impl_opengl3.cpp259-264
Every platform backend must implement four core functions:
| Function | Purpose | Called By |
|---|---|---|
ImGui_Impl[Platform]_Init() | Initialize backend, allocate resources | Application during startup |
ImGui_Impl[Platform]_Shutdown() | Cleanup backend, free resources | Application during shutdown |
ImGui_Impl[Platform]_NewFrame() | Update display size, time delta, input state | Application each frame before ImGui::NewFrame() |
ImGui_Impl[Platform]_ProcessEvent() | Process platform events (optional but recommended) | Application event loop |
Initialization Pattern:
Example from Win32 backend initialization:
The Win32 backend shows the typical initialization structure at backends/imgui_impl_win32.cpp159-211 Key steps:
io.BackendPlatformUserDataio.BackendPlatformName = "imgui_impl_win32"ImGuiBackendFlags_HasMouseCursors)PlatformHandle for the main windowSources: backends/imgui_impl_win32.cpp159-211 backends/imgui_impl_glfw.cpp512-581
Platform backends should set appropriate flags in io.BackendFlags during initialization:
| Flag | Meaning | Set By | Requirements |
|---|---|---|---|
ImGuiBackendFlags_HasMouseCursors | Backend can change mouse cursor shape | Platform | Call glfwCreateStandardCursor() or SDL_CreateSystemCursor() or LoadCursor() |
ImGuiBackendFlags_HasSetMousePos | Backend can reposition mouse | Platform | Handle io.WantSetMousePos via glfwSetCursorPos() or SDL_WarpMouseInWindow() |
ImGuiBackendFlags_HasGamepad | Backend provides gamepad input | Platform | Update io via io.AddKeyAnalogEvent() for gamepad axes/buttons |
Example from Win32 backend initialization:
Example from GLFW backend initialization:
Sources: backends/imgui_impl_win32.cpp175-178 backends/imgui_impl_glfw.cpp542-551
Platform backends feed input to ImGui through the ImGuiIO API. The pattern is to process platform-specific events and translate them to ImGui events.
Input Event Translation: Platform Events to ImGuiIO API
Example: SDL3 Mouse Motion Event Processing
Example: GLFW Key Callback Translation
Complete ImGuiIO Input API:
| Function | Purpose | Example |
|---|---|---|
io.AddMousePosEvent(x, y) | Mouse position in window coordinates | io.AddMousePosEvent(event->motion.x, event->motion.y) |
io.AddMouseButtonEvent(button, down) | Mouse button press/release (0-4) | io.AddMouseButtonEvent(0, action == GLFW_PRESS) |
io.AddMouseWheelEvent(x, y) | Mouse wheel scroll delta | io.AddMouseWheelEvent(xoffset, yoffset) |
io.AddMouseSourceEvent(source) | Discriminate Mouse/Touch/Pen | io.AddMouseSourceEvent(ImGuiMouseSource_TouchScreen) |
io.AddKeyEvent(key, down) | Keyboard key press/release | io.AddKeyEvent(ImGuiKey_Space, true) |
io.AddInputCharacter(c) | Unicode text input | io.AddInputCharacter(event->text.text[0]) |
io.AddFocusEvent(focused) | Window gained/lost focus | io.AddFocusEvent(event->type == SDL_EVENT_WINDOW_FOCUS_GAINED) |
io.SetKeyEventNativeData(key, native_keycode, scancode) | Store native key data for legacy compatibility | io.SetKeyEventNativeData(key, keycode, scancode, scancode) |
Sources: backends/imgui_impl_sdl3.cpp380-483 backends/imgui_impl_glfw.cpp419-486 backends/imgui_impl_win32.cpp595-841
NewFrame() must update timing and display information each frame:
Required updates:
io.DisplaySize = ImVec2(width, height)io.DisplayFramebufferScale = ImVec2(scale_x, scale_y) (for retina/high-DPI)io.DeltaTime = time_elapsed_since_last_frameExample from GLFW backend:
The GLFW backend's NewFrame at backends/imgui_impl_glfw.cpp866-925 shows:
Sources: backends/imgui_impl_glfw.cpp866-925 backends/imgui_impl_sdl3.cpp729-800 backends/imgui_impl_win32.cpp426-504
Shutdown() must clean up all resources allocated during Init():
Typical cleanup steps:
io.BackendPlatformUserDataio.BackendPlatformName and io.BackendPlatformUserDataio.BackendFlagsplatform_io.ClearPlatformHandlers()Example pattern:
Sources: backends/imgui_impl_glfw.cpp593-606 backends/imgui_impl_win32.cpp224-242 backends/imgui_impl_sdl3.cpp599-620
Clipboard Support:
Implement clipboard by setting handlers in ImGuiPlatformIO:
Mouse Cursor Shape:
If supporting ImGuiBackendFlags_HasMouseCursors, update cursor in NewFrame():
ImGui::GetMouseCursor() to get desired cursorIME (Input Method Editor) Support:
For text input in CJK languages, implement IME callback:
The callback receives ImGuiPlatformImeData with input position and should show/hide the IME candidate window accordingly.
Sources: backends/imgui_impl_glfw.cpp554-562 backends/imgui_impl_sdl3.cpp169-207 backends/imgui_impl_win32.cpp860-894
Every renderer backend must implement four core functions:
| Function | Purpose | Called By |
|---|---|---|
ImGui_Impl[Renderer]_Init() | Initialize rendering resources (shaders, pipeline, etc.) | Application during startup |
ImGui_Impl[Renderer]_Shutdown() | Cleanup rendering resources | Application during shutdown |
ImGui_Impl[Renderer]_NewFrame() | Prepare for new frame (optional, used for per-frame setup) | Application each frame before ImGui::NewFrame() |
ImGui_Impl[Renderer]_RenderDrawData(ImDrawData*) | Render ImGui draw commands to screen | Application after ImGui::Render() |
Renderer backends should set appropriate flags in io.BackendFlags during initialization:
| Flag | Meaning | Requirements |
|---|---|---|
ImGuiBackendFlags_RendererHasVtxOffset | Supports large meshes (64k+ vertices) with 16-bit indices | Use ImDrawCmd::VtxOffset when rendering |
ImGuiBackendFlags_RendererHasTextures | Supports dynamic texture creation/updates | Implement texture management functions |
The RendererHasVtxOffset flag is critical for rendering large meshes efficiently. When set, ImGui can use 16-bit indices even for meshes with 64k+ vertices by using a vertex offset.
Sources: backends/imgui_impl_vulkan.cpp1197-1198 backends/imgui_impl_opengl3.cpp368-371
Renderer backend initialization typically involves creating rendering pipeline state:
Example from Vulkan backend:
The Vulkan backend initialization at backends/imgui_impl_vulkan.cpp1146-1235 shows:
Example from OpenGL3 backend:
The OpenGL3 backend initialization at backends/imgui_impl_opengl3.cpp306-418 shows:
platform_io.Renderer_TextureMaxWidth/HeightSources: backends/imgui_impl_vulkan.cpp1146-1235 backends/imgui_impl_opengl3.cpp306-418 backends/imgui_impl_dx12.cpp741-899
RenderDrawData() is the core rendering function that translates ImDrawData into graphics API commands. This is where most of the backend complexity lies.
ImDrawData Structure: Memory Layout and Key Fields
RenderDrawData Implementation Steps:
Key Implementation Details:
pcmd->GetTexID() instead of pcmd->TextureId:Example: Vulkan RenderDrawData Structure
The Vulkan backend demonstrates the complete flow at backends/imgui_impl_vulkan.cpp523-676:
Example from OpenGL3 backend:
The OpenGL3 rendering at backends/imgui_impl_opengl3.cpp524-704 demonstrates:
Sources: backends/imgui_impl_vulkan.cpp513-676 backends/imgui_impl_opengl3.cpp524-704 backends/imgui_impl_dx12.cpp241-457
Some ImDrawCmd entries have special UserCallback values that must be handled:
Draw Callback Handling Logic
Example from Vulkan backend:
Example from OpenGL3 backend:
Callback Types:
| Callback Value | Purpose | Handler Action |
|---|---|---|
nullptr | Normal draw command | Execute scissor, bind texture, issue draw call |
ImDrawCallback_ResetRenderState | Reset all render state | Call SetupRenderState() function to restore pipeline/viewport/etc. |
| Custom function pointer | User-defined callback | Execute pcmd->UserCallback(draw_list, pcmd) |
Sources: backends/imgui_impl_vulkan.cpp608-626 backends/imgui_impl_opengl3.cpp657-677
Backends supporting ImGuiBackendFlags_RendererHasTextures must implement three handler functions for dynamic texture management.
Texture Lifecycle State Machine
Required Handler Functions:
Register these handlers during Init():
Required Handler Functions:
Register these handlers during Init():
1. Renderer_CreateTexture Handler:
Called when ImTextureData::Status == ImTextureStatus_WantCreate.
2. Renderer_UpdateTexture Handler:
Called when ImTextureData::Status == ImTextureStatus_WantUpdate.
3. Renderer_DestroyTexture Handler:
Called when ImTextureData::Status == ImTextureStatus_WantDestroy.
RenderDrawData Integration:
Process texture updates at the start of RenderDrawData():
This ensures all textures are created/updated before they're referenced in draw commands.
Key ImTextureData Fields:
| Field | Type | Purpose |
|---|---|---|
Status | ImTextureStatus | Current state (WantCreate/OK/WantUpdate/WantDestroy) |
Width, Height | int | Texture dimensions in pixels |
PixelsRGBA32 | unsigned int* | RGBA32 pixel data (width * height * 4 bytes) |
UpdateRegion | ImRect | Optional: Region to update (for partial updates) |
RendererData | void* | Backend-specific texture data (e.g., ImGui_ImplVulkan_Texture*) |
TextureID | ImTextureID | Texture identifier for ImDrawCmd::GetTexID() (e.g., VkDescriptorSet) |
Sources: backends/imgui_impl_vulkan.cpp873-1064 backends/imgui_impl_opengl3.cpp766-927 backends/imgui_impl_dx12.cpp518-734
Some renderer backends use NewFrame() for per-frame setup:
Example from OpenGL3:
This ensures shaders are compiled on-demand if they were destroyed.
Sources: backends/imgui_impl_opengl3.cpp441-451
Shutdown() must release all rendering resources:
Typical cleanup steps:
platform_io.ClearRendererHandlers()Example pattern:
Sources: backends/imgui_impl_vulkan.cpp1237-1253 backends/imgui_impl_opengl3.cpp421-439
Here's the complete sequence for integrating ImGui with custom backends:
Sources: Diagram 5 from high-level context, docs/EXAMPLES.md20-36
To support multiple ImGui contexts (advanced usage):
ImGui::GetCurrentContext()Note: Platform backends have additional complexity with multi-context support because platform events (like GLFW callbacks) are global and don't know which ImGui context they belong to. Consider using ImGuiContext mapping if supporting multiple windows.
Sources: backends/imgui_impl_glfw.cpp175-179 backends/imgui_impl_glfw.cpp226-232
Renderer State Isolation:
ImGuiConfigFlags_DebugNoDefaultClipboard if they handle it themselvesExample from DirectX11: The DX11 backend backs up extensive state at backends/imgui_impl_dx11.cpp164-220 including:
This ensures ImGui rendering doesn't corrupt the application's rendering state.
Sources: backends/imgui_impl_dx11.cpp164-220 backends/imgui_impl_opengl3.cpp524-579
Buffer Management:
Minimize State Changes:
Texture Updates:
tex->UpdateRegion)Sources: backends/imgui_impl_vulkan.cpp434-466 backends/imgui_impl_dx12.cpp1183-1263
Always validate:
Example pattern:
Sources: backends/imgui_impl_vulkan.cpp513-519 backends/imgui_impl_opengl3.cpp524-531
Follow these conventions for consistency:
imgui_impl_[platform/renderer].cpp/hImGui_Impl[Name]_"imgui_impl_[name]" stored in io.BackendPlatformName or io.BackendRendererNameImGui_Impl[Name]_DataImGui_Impl[Name]_GetBackendData()Sources: backends/imgui_impl_glfw.cpp1-4 backends/imgui_impl_vulkan.cpp1-2
Provide clear documentation in the header file:
Example header template:
Sources: backends/imgui_impl_glfw.h1-16 backends/imgui_impl_vulkan.cpp1-27
To verify your backend implementation:
Use ImGui::ShowDemoWindow() as a comprehensive test case - it exercises all major features.
Sources: docs/EXAMPLES.md10 docs/BACKENDS.md21-23
Key files to study:
ImGui core header references:
imgui.h - Core API including ImGuiIO and input functionsimgui_internal.h - Internal structures (not typically needed for backends)Example applications:
Refresh this wiki