# Handling High-DPI Displays and Viewport Scaling with Dear ImGui

> Master high-DPI displays & viewport scaling in Dear ImGui. Learn to configure DPI scaling for fonts & viewports using backend helpers and imgui flags for crisp UIs.

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

---

**Dear ImGui handles high-DPI displays through per-viewport `Scale` factors and global `DisplayFramebufferScale`, configured via `ConfigDpiScaleFonts` and `ConfigDpiScaleViewports` flags in the docking branch, combined with platform-specific backend helpers like `ImGui_ImplWin32_EnableDpiAwareness()`.**

Dear ImGui provides comprehensive support for high-DPI (HiDPI) and per-monitor DPI scaling through a combination of IO configuration flags and backend-specific helpers. Whether you are targeting Retina displays on macOS or mixed-DPI monitor setups on Windows, the library's viewport system in `ocornut/imgui` automatically propagates scaling factors to render crisp UI at any resolution. This guide examines the source-level implementation to show exactly how display scaling works and how to configure it correctly.

## Understanding the Core DPI Architecture

Dear ImGui separates DPI handling into **global display metrics** and **per-viewport scaling factors**, allowing the interface to adapt when windows move between monitors with different densities.

### DisplayFramebufferScale

The global density of the primary display is stored in `ImGuiIO::DisplayFramebufferScale` (defined in [[`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) around line 2420](https://github.com/ocornut/imgui/blob/master/imgui.h#L2420)). This `ImVec2` represents the ratio between device pixels and logical pixels (e.g., `2.0, 2.0` for Retina displays). The value feeds into each viewport's `FramebufferScale` and is used by the renderer to determine fringe sizes and line thicknesses.

### Per-Viewport Scale Factors

Each `ImGuiViewport` structure maintains its own `Scale` value (see [[`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) line 3486](https://github.com/ocornut/imgui/blob/master/imgui.h#L3486)). This factor is derived from the platform window's DPI and is applied to all UI geometry when the viewport is drawn. During `NewFrame()`, the backend updates the runtime DPI scale in `CurrentDpiScale` (handled in [[`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp) line 4688](https://github.com/ocornut/imgui/blob/master/imgui.cpp#L4688)), which propagates to `ImDrawData::FramebufferScale` for the rendering pipeline.

## Automatic Scaling Configuration (Docking Branch)

The docking branch introduces automatic DPI handling through two critical configuration flags defined near [[`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) lines 2296-2298](https://github.com/ocornut/imgui/blob/master/imgui.h#L2296-L2298):

- **`ConfigDpiScaleFonts`**: When enabled, Dear ImGui automatically rebuilds the font atlas with sizes multiplied by `FontScaleDpi`, ensuring text remains sharp when moving between monitors.
- **`ConfigDpiScaleViewports`**: Enables automatic scaling of the entire UI when the monitor DPI changes, adjusting layout calculations without manual intervention.

Configure these before your first `NewFrame()`:

```cpp
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;    // Required for per-monitor scaling
io.ConfigDpiScaleFonts = true;                         // Auto-rebuild fonts for DPI
io.ConfigDpiScaleViewports = true;                     // Auto-scale UI elements

```

## Platform-Specific DPI Awareness

Dear ImGui relies on the underlying windowing backend to provide accurate DPI information. Each platform requires specific initialization to declare DPI awareness.

### Windows (Win32)

For Windows applications, call the backend helper before creating your window. In [[`imgui_impl_win32.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_win32.cpp) (lines 24-30)](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_win32.cpp#L24-L30), Dear ImGui provides `ImGui_ImplWin32_EnableDpiAwareness()`, which wraps `SetProcessDpiAwarenessContext()`:

```cpp
// Enable DPI awareness before any window creation
ImGui_ImplWin32_EnableDpiAwareness();

// Or manually for older Windows versions:
::SetProcessDPIAware();

```

### SDL2

Pass the `SDL_WINDOW_ALLOW_HIGHDPI` flag when creating your window, and include the Windows-specific DPI awareness call when building for that platform:

```cpp
SDL_Window* window = SDL_CreateWindow(
    "Demo", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
    1280, 720,
    SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);

#ifdef _WIN32
::SetProcessDPIAware();  // Required for correct DPI reporting on Windows
#endif

```

### GLFW

Enable per-monitor scaling in GLFW to ensure `glfwGetMonitorContentScale` returns correct values, which the backend uses to populate viewport scales:

```cpp
// Before glfwCreateWindow()
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);

// Alternative: query scale manually for custom handling
float xscale, yscale;
glfwGetMonitorContentScale(monitor, &xscale, &yscale);

```

## Handling Custom Geometry and Style Scaling

When `ConfigDpiScaleFonts` is disabled, or when implementing custom draw calls, you must manually multiply coordinates by the current DPI scale to maintain visual consistency.

Manual style scaling requires multiplying `ImGuiStyle` fields (such as `CellPadding` and `FrameRoundings`) by your DPI factor, as the automatic viewport scaling only affects built-in layout calculations (see handling in [[`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp) around line 9194](https://github.com/ocornut/imgui/blob/master/imgui.cpp#L9194)).

For custom drawing, retrieve the scale from the current viewport:

```cpp
ImGuiViewport* vp = ImGui::GetWindowViewport();
float dpiScale = vp->Scale;  // Matches io.DisplayFramebufferScale.x

// Scale custom primitives
ImDrawList* dl = ImGui::GetWindowDrawList();
dl->AddCircle(
    ImVec2(100, 100) * dpiScale, 
    10.0f * dpiScale, 
    ImGui::GetColorU32(ImGuiCol_Text)
);

```

## Complete Implementation Example

Here is a complete workflow integrating platform setup, ImGui initialization, and runtime DPI handling:

```cpp
// 1. Platform DPI setup (Win32 example)
ImGui_ImplWin32_EnableDpiAwareness();

// 2. Create SDL2 window with HiDPI support
SDL_Window* window = SDL_CreateWindow(
    "High-DPI ImGui", 
    SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
    1280, 720, 
    SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);

// 3. Initialize ImGui with viewport and auto-scaling
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
io.ConfigDpiScaleFonts = true;
io.ConfigDpiScaleViewports = true;

// 4. Runtime DPI inspection
ImGui::NewFrame();
ImGui::Text("Display Scale: %.2f", io.DisplayFramebufferScale.x);

// Move window between monitors to see automatic scale updates
ImGuiViewport* vp = ImGui::GetMainViewport();
ImGui::Text("Viewport Scale: %.2f", vp->Scale);

```

## Summary

- **`DisplayFramebufferScale`** in `ImGuiIO` stores the global display density and feeds into rendering calculations for line thickness and anti-aliasing.
- **`Viewport::Scale`** provides per-monitor DPI factors that automatically adjust when windows move between displays of different densities.
- **`ConfigDpiScaleFonts`** and **`ConfigDpiScaleViewports`** (docking branch only) enable automatic font atlas rebuilding and UI scaling without manual intervention.
- **Platform backends** must declare DPI awareness via `ImGui_ImplWin32_EnableDpiAwareness()`, `SDL_WINDOW_ALLOW_HIGHDPI`, or `GLFW_SCALE_TO_MONITOR` to report correct scale values.
- **Custom draw calls** require manual multiplication by `viewport->Scale` when automatic viewport scaling is disabled or for non-standard primitives.

## Frequently Asked Questions

### Why does my text appear blurry on high-DPI displays?

Blurry text typically indicates that the font atlas was generated at a low resolution and is being stretched by the display scale. Enable `io.ConfigDpiScaleFonts = true` (docking branch) to automatically rebuild fonts at the correct pixel density, or manually load fonts multiplied by `io.DisplayFramebufferScale.x` before calling `ImGui::NewFrame()`.

### What is the difference between `DisplayFramebufferScale` and `Viewport->Scale`?

`DisplayFramebufferScale` in `ImGuiIO` represents the primary monitor's density and affects global rendering parameters like anti-aliasing fringe sizes. `Viewport->Scale` is specific to each window and updates when the viewport moves to a monitor with different DPI. When multi-viewport support is enabled, Dear ImGui uses the per-viewport scale for layout calculations while the framebuffer scale handles draw data output.

### Do I need the docking branch to support high-DPI displays?

No, but the docking branch provides automatic handling through `ConfigDpiScaleFonts` and `ConfigDpiScaleViewports`. In the master branch, you must manually detect DPI changes using platform APIs (like `glfwGetMonitorContentScale`), reload fonts with scaled sizes, and adjust `ImGui::GetStyle()` metrics accordingly.

### How do I scale my own ImDrawList geometry to match ImGui's DPI handling?

Query the current viewport's scale factor and multiply your coordinates and sizes by this value. Retrieve the scale via `ImGui::GetWindowViewport()->Scale` or `ImGui::GetMainViewport()->Scale`, then apply it to all `AddCircle`, `AddRect`, and vertex positions in your custom draw lists to ensure they align with automatically-scaled ImGui widgets.