# How to Handle DPI Scaling and High‑DPI Displays in ImGui Applications

> Learn how ImGui handles high DPI displays and DPI scaling in your applications. Understand ImGuiIO::DisplayFramebufferScale for adapting your UI to different pixel densities.

- Repository: [omar/imgui](https://github.com/ocornut/imgui)
- Tags: how-to-guide
- Published: 2026-07-15

---

**Dear ImGui handles high‑DPI displays by separating logical UI coordinates from physical pixels via `ImGuiIO::DisplayFramebufferScale`, which back‑ends populate by querying the OS DPI and dividing by 96.**

Dear ImGui (`ocornut/imgui`) renders crisp, resolution‑independent interfaces by decoupling the logical size of widgets from the physical pixel density of the monitor. The core mechanism relies on `ImGuiIO::DisplayFramebufferScale`, defined in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h), which back‑ends set by detecting the native DPI and computing a scale factor relative to the standard 96 DPI baseline.

## How ImGui Implements DPI Scaling Internally

### The DisplayFramebufferScale Mechanism

The `ImGuiIO::DisplayFramebufferScale` field (located at line 2420 in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h)) tells the library how many physical pixels correspond to one logical UI unit. When this value is greater than 1.0—for example, 2.0 on a Retina display—the library automatically adjusts three critical subsystems.

### Automatic Scaling Behaviors

- **Font atlas generation**: The font system multiplies the requested pixel size by `DisplayFramebufferScale` before rasterizing glyphs, ensuring text remains sharp rather than pixel‑doubled.
- **Geometry submission**: Vertex positions for all widgets are multiplied by the scale during the draw list phase, keeping buttons and windows the same visual size regardless of resolution.
- **Mouse input normalization**: Incoming cursor coordinates are divided by the scale factor so that `io.MousePos` matches the logical coordinate space used by the UI.

## Platform Backend DPI Detection

ImGui does not query the OS directly; instead, the platform back‑end detects the monitor DPI and writes the result to `io.DisplayFramebufferScale`. The official back‑ends implement this as follows:

### Win32 Implementation

In [`backends/imgui_impl_win32.cpp`](https://github.com/ocornut/imgui/blob/main/backends/imgui_impl_win32.cpp) (lines 27‑40), the `ImGui_ImplWin32_GetDpiScaleForMonitor()` function uses `GetDpiForMonitor` on Windows 8.1 and later, falling back to `GetDeviceCaps(LOGPIXELSX)` for older systems. The resulting value is stored in `io.DisplayFramebufferScale` inside `ImGui_ImplWin32_NewFrame()`.

### SDL2 and SDL3 Handling

The SDL2 back‑end in [`backends/imgui_impl_sdl2.cpp`](https://github.com/ocornut/imgui/blob/main/backends/imgui_impl_sdl2.cpp) (lines 75‑81) calls `SDL_GetDisplayDPI()` and clamps values below 96 to the baseline. It then computes `scale = dpi / 96.0f` and assigns it to the IO structure.

### GLFW Support

For GLFW on Windows, [`imgui_impl_glfw.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_glfw.cpp) (lines 93‑95) invokes `ImGui_ImplWin32_GetLegacyDpiScale()`, which reads `LOGPIXELSX` from a device context to determine the scale factor.

## Implementing DPI Scaling in Your Application

### Standard Integration Workflow

When using an official back‑end, DPI handling is automatic. Initialize ImGui, call the back‑end’s `NewFrame()` function, and the scale is applied before you build any UI:

```cpp
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;  // optional

// Platform and renderer back‑ends populate io.DisplayFramebufferScale
ImGui_ImplWin32_NewFrame();  // or ImGui_ImplSDL2_NewFrame, etc.
ImGui_ImplDX11_NewFrame();

ImGui::NewFrame();
ImGui::ShowDemoWindow();
ImGui::Render();

ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());

```

### Handling Dynamic DPI Changes

Update the scale factor whenever the window moves to a different monitor:

- **Win32**: Listen for `WM_DPICHANGED` and recompute the scale.
- **SDL2**: Watch for `SDL_EVENT_DISPLAY_ORIENTATION` or similar display events.
- **GLFW**: `glfwGetMonitorContentScale` returns updated values after `glfwPollEvents`.

## Building Custom Back‑Ends for High‑DPI

If you are writing a custom platform layer, follow these steps:

1. **Detect native DPI** using OS‑specific APIs (e.g., `GetDpiForMonitor` on Windows, `SDL_GetDisplayDPI` on SDL, or `glfwGetMonitorContentScale` on GLFW).
2. **Compute the scale** as `dpi / 96.0f` (96 DPI is the baseline).
3. **Assign the scale** to `io.DisplayFramebufferScale = ImVec2(scale, scale);`.
4. **Transform mouse coordinates** by dividing incoming positions by `scale` so that `io.MousePos` aligns with the logical UI space.

## Multi‑Viewport DPI Considerations

When `ImGuiConfigFlags_ViewportsEnable` is active, each OS window may reside on a monitor with different pixel density. ImGui creates a separate `ImGuiViewport` for each platform window, storing an independent `FramebufferScale` per viewport.

The platform back‑end must set `viewport->Flags |= ImGuiViewportFlags_IsPlatformWindow;` and update `viewport->FramebufferScale` during its `NewFrame` processing. The official back‑ends handle this automatically, ensuring that a viewport dragged from a 96 DPI monitor to a 200 DPI Retina display updates its scale dynamically.

## Summary

- **DPI handling is back‑end driven**: The core library consumes `io.DisplayFramebufferScale` but never queries the OS.
- **Official back‑ends are ready**: Win32, SDL2/3, GLFW, and macOS back‑ends already implement robust DPI detection in `imgui_impl_*.cpp`.
- **Scale calculation**: Always divide the native DPI by 96.0f to obtain the correct framebuffer scale.
- **Dynamic updates**: Recompute the scale on monitor changes or `WM_DPICHANGED` events to support mixed‑DPI setups.
- **Multi‑viewport support**: Each `ImGuiViewport` maintains its own `FramebufferScale` for per‑monitor DPI awareness.

## Frequently Asked Questions

### How does ImGui handle font scaling on high‑DPI displays?

ImGui multiplies the font size by `DisplayFramebufferScale` before rasterizing the glyph atlas. This means a 16px font at 2.0x DPI is rendered at 32 physical pixels, producing crisp text rather than upscaled bitmaps.

### What is the baseline DPI value used for scaling calculations?

The baseline is **96 DPI**, the standard Windows logical resolution. Back‑ends compute the scale factor as `scale = native_dpi / 96.0f`, which is why SDL2 clamps values below 96 to prevent incorrect scaling on legacy displays.

### How do I update DPI scaling when a window moves between monitors?

Listen for the platform‑specific DPI change event (e.g., `WM_DPICHANGED` on Win32) inside your window message loop. Recompute `io.DisplayFramebufferScale` using the new monitor’s DPI, and call `ImGui::GetIO().Fonts->Build()` to regenerate the font atlas if the scale changes significantly.

### Why are my mouse coordinates incorrect on a high‑DPI display?

If you are bypassing the official back‑end input helpers, you must divide incoming mouse coordinates by `io.DisplayFramebufferScale` before writing them to `io.MousePos`. The official back‑ends perform this normalization automatically in their `NewFrame` implementations.