How to Handle DPI Scaling in Dear ImGui Applications: A Complete Implementation Guide
Dear ImGui handles DPI scaling through a three-layer architecture that requires OS-level DPI awareness, ImGuiIO configuration flags such as io.ConfigDpiScaleFonts, and runtime scaling factors including style.FontScaleDpi that the application must wire together before the first frame.
Dear ImGui (ocornut/imgui) provides robust support for high-DPI monitors through a deliberate design that separates platform responsibilities from UI scaling logic. To handle DPI scaling in Dear ImGui applications effectively, you must coordinate three distinct layers: operating system declarations, backend configuration flags, and internal style variables that control font rasterization and widget geometry.
The Three-Layer DPI Architecture
DPI scaling in Dear ImGui is intentionally split into three independent concerns that your application must connect:
-
OS-Level DPI Awareness: Prevents the operating system from automatically bitmap-scaling your window, which would produce blurry output. On Windows, this is implemented in
ImGui_ImplWin32_EnableDpiAwareness()insidebackends/imgui_impl_win32.cpp#L24-L30. On SDL2, you use theSDL_WINDOW_ALLOW_HIGHDPIflag, while GLFW relies onGLFW_SCALE_TO_MONITOR. -
ImGuiIO Configuration Flags: Boolean switches that tell Dear ImGui to automatically update scaling variables when the monitor DPI changes. According to
docs/FAQ.md#L792, settingio.ConfigDpiScaleFontstotrueenables automatic overwriting ofstyle.FontScaleDpi, whileio.ConfigDpiScaleViewportsadditionally scales platform windows in the docking branch. -
Internal Scaling Factors: Runtime values multiplied into geometry calculations. These include
g.Style._MainScale(accessed viaGetScale()inimgui_internal.h#L3348),style.FontScaleDpi(declared inimgui.h#L2314), andio.MouseCursorScale(defined inimgui.h#L2375). These are initialized inimgui.cpp#L1511and applied to window sizes atimgui.cpp#L9217.
This separation exists because OS awareness is required to get a 1:1 framebuffer, while ImGui’s internal flags provide the library freedom to decide when and how to apply scaling without breaking user customizations.
Step 1: Enable OS-Level DPI Awareness
You must declare DPI awareness before creating your window. Failure to do so results in the OS scaling the framebuffer automatically, making Dear ImGui’s own scaling redundant and producing blurry fonts.
-
Windows: Call
ImGui_ImplWin32_EnableDpiAwareness()prior toCreateWindow(). This helper usesSetProcessDpiAwarenessContext()when available, falling back toSetProcessDPIAware()on older systems. -
SDL2: Pass the
SDL_WINDOW_ALLOW_HIGHDPIflag toSDL_CreateWindow(), as demonstrated inexamples/example_sdl2_opengl3/main.cpp#L84. -
GLFW: Set
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE)before window creation, or rely on the default high-DPI handling shown inexamples/example_glfw_opengl3/main.cpp#L92. -
macOS: The native backend already supports HiDPI; no extra call is required.
Step 2: Configure Automatic DPI Scaling
Once the window is DPI-aware, enable Dear ImGui’s automatic scaling in the docking branch by setting two flags in your initialization code:
ImGuiIO& io = ImGui::GetIO();
io.ConfigDpiScaleFonts = true; // Auto-updates style.FontScaleDpi
io.ConfigDpiScaleViewports = true; // Also scales platform windows
When io.ConfigDpiScaleFonts is enabled, Dear ImGui automatically overwrites style.FontScaleDpi whenever the monitor DPI changes, as noted in the initialization code at imgui.cpp#L1511. If you prefer manual control, leave these as false and assign style.FontScaleDpi yourself, as shown in examples/example_win32_opengl3/main.cpp#L77.
Step 3: Understand Internal Scaling Factors
Dear ImGui applies three distinct scales during rendering:
-
Global UI Scale (
g.Style._MainScale): Retrieved viaGetScale()inimgui_internal.h#L3348, this factor affects widget thickness, window padding, and layout spacing. -
Font DPI Scale (
style.FontScaleDpi): Declared inimgui.h#L2314, this multiplier is applied to text geometry during glyph rasterization. It allows fonts to scale independently of the global UI scale. -
Mouse Cursor Scale (
io.MouseCursorScale): Defined inimgui.h#L2375, this scales software-rendered mouse cursors to match the DPI.
You can set an initial manual base scale before the auto-scale system kicks in:
ImGuiStyle& style = ImGui::GetStyle();
style.FontScaleDpi = 1.5f; // Start at 150% font size
Handling Per-Monitor DPI Changes
For applications that span multiple monitors with different DPIs, query the scale factor each frame or when the window moves. The Win32 backend provides ImGui_ImplWin32_GetDpiScaleForMonitor() for this purpose. Internally, Dear ImGui stores the current monitor’s scale in g.CurrentDpiScale (see imgui.cpp#L4700), which the docking branch uses to update viewport scaling automatically when io.ConfigDpiScaleViewports is enabled.
If you are not using the docking branch, manually multiply the OS-reported DPI scale (e.g., from SDL’s SDL_GetWindowDisplayScale or GLFW’s glfwGetWindowContentScale) into style.FontScaleDpi and io.MouseCursorScale during your main loop.
Complete Cross-Platform Implementation
The following snippet demonstrates the full initialization flow for Win32, SDL2, and GLFW backends:
// ------------------------------------------------------------
// 1. Create a DPI-aware window (platform-specific)
// ------------------------------------------------------------
#if defined(_WIN32)
// Win32 – ask Windows to make the process DPI-aware
ImGui_ImplWin32_EnableDpiAwareness(); // → backends/imgui_impl_win32.cpp
// Create your Win32 window as usual (hwnd)
#elif defined(__APPLE__) && defined(__MACH__)
// macOS – the native backend already supports HiDPI; no extra call needed
// Create NSWindow/GLFW window normally
#else
// SDL2 example (works for both SDL2 and SDL3)
SDL_Window* window = SDL_CreateWindow(
"My ImGui App",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
1280, 720,
SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
#endif
// ------------------------------------------------------------
// 2. Initialise ImGui (common to all back-ends)
// ------------------------------------------------------------
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
// Enable ImGui's own DPI handling (requires docking branch)
// This will automatically rewrite style.FontScaleDpi whenever the monitor DPI changes.
io.ConfigDpiScaleFonts = true; // scales fonts
io.ConfigDpiScaleViewports = true; // also scales platform windows (if you use viewports)
// Optional: set a manual base scale before the auto-scale runs
ImGuiStyle& style = ImGui::GetStyle();
style.FontScaleDpi = 1.2f; // start at 120% font size
// ------------------------------------------------------------
// 3. Backend-specific init (example for Win32)
// ------------------------------------------------------------
#if defined(_WIN32)
ImGui_ImplWin32_Init(hwnd);
#elif defined(__APPLE__) && defined(__MACH__)
ImGui_ImplOSX_Init();
#else
ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
#endif
// ------------------------------------------------------------
// 4. Main loop – ImGui will now use the DPI-aware scalings automatically
// ------------------------------------------------------------
while (!done)
{
// Platform event handling...
ImGui_Impl..._NewFrame();
ImGui::NewFrame();
// Your UI code here
ImGui::Text("DPI-aware window");
ImGui::Render();
ImGui_Impl..._RenderDrawData(ImGui::GetDrawData());
}
Summary
- OS awareness comes first: Call
ImGui_ImplWin32_EnableDpiAwareness()or useSDL_WINDOW_ALLOW_HIGHDPIbefore creating the window to prevent OS-level bitmap scaling. - Enable automatic handling: Set
io.ConfigDpiScaleFontsandio.ConfigDpiScaleViewportstotruein the docking branch to let Dear ImGui managestyle.FontScaleDpiautomatically. - Three scales control rendering:
g.Style._MainScalefor UI geometry,style.FontScaleDpifor text, andio.MouseCursorScalefor cursors. - Manual fallback: If not using the docking branch, query the monitor DPI via your platform API and assign the scale factor to
style.FontScaleDpidirectly.
Frequently Asked Questions
Does DPI scaling require the docking branch of Dear ImGui?
The automatic scaling flags io.ConfigDpiScaleFonts and io.ConfigDpiScaleViewports are only available in the docking branch. If you are using the master branch, you must manually calculate the DPI scale using ImGui_ImplWin32_GetDpiScaleForMonitor() or equivalent platform functions, then assign the value to style.FontScaleDpi each frame.
Why do my fonts appear blurry even after calling EnableDpiAwareness?
Blurriness indicates that the OS is still bitmap-scaling your framebuffer. Verify that you called ImGui_ImplWin32_EnableDpiAwareness() before creating the window, and ensure your graphics API backend (OpenGL, DirectX, Vulkan) is creating a backbuffer at the full native resolution rather than a scaled resolution.
How do I calculate the correct scale factor for a specific monitor?
On Windows, use ImGui_ImplWin32_GetDpiScaleForMonitor() provided in the Win32 backend. For SDL2, call SDL_GetWindowDisplayScale(window). For GLFW, use glfwGetWindowContentScale(window, &xscale, &yscale). Multiply this value by your base style.FontScaleDpi to get the final scale.
Can I use different scale factors for different viewports when using multi-viewports?
Yes. When io.ConfigDpiScaleViewports is enabled in the docking branch, Dear ImGui automatically applies per-viewport scaling based on the monitor each viewport resides on. The internal variable g.CurrentDpiScale (see imgui.cpp#L4700) tracks this per-viewport value, ensuring that platform windows render at the correct DPI regardless of which monitor they occupy.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →