microsoft / microsoft/microsoft-ui-xaml

Proposal: let WinUI 3 windows skip the GDI redirection surface

Open
#11,523 7 comments 19 reactions 1 assignee Claimed by @JesseCol View on GitHub
area-XamlWindow feature proposal team-Core
Dominant language
C++
Stars
8.4k
Forks
942
Avg merge
2d 7h
Merged PRs (30d)
105

Description

### Title

Let WinUI 3 windows skip the GDI redirection surface

### Summary

A WinUI 3 window renders its content through a composition island, but its top-level window is still created with a GDI redirection surface that the framework never meaningfully draws into. That surface costs one full-window 32-bit bitmap of memory each, a measured 7.91 MB for a 1080p window, and is blended by the compositor on every frame despite contributing nothing.

This proposes an opt-in that creates the window with `WS_EX_NOREDIRECTIONBITMAP`, so apps that don't paint their window with GDI stop paying for it.

### Rationale

* **It is a real, measurable amount of memory, on every window.** The cost is exactly one 32-bit bitmap the size of the window, so it scales with window area and multiplies with the number of windows an app opens. A maximized window on a 4K display works out to roughly 32 MB by that formula.

* **Developers cannot see this cost, so they cannot diagnose or act on it.** The surface is allocated and owned by the compositor process, not by the app that owns the window. An app's own memory counters never move, so this is invisible in ordinary app-side profiling and easy to misattribute to something else. It only shows up if you know to measure `dwm.exe`, and even then only by differencing before and after window creation.

* **It is not just memory. The compositor blends that surface every frame.** An extra full-window surface that contributes nothing still participates in composition.

* **There is currently no way for an app to avoid it.** `WS_EX_NOREDIRECTIONBITMAP` only takes effect at window creation, and the framework creates the window. An app cannot apply the style afterwards, and cannot pass it in, so today this is a fixed price on every WinUI 3 window.

* **It cannot be avoided by simply not painting, either.** The surface is allocated for any redirected window regardless of whether anything ever draws into it (see the measurements below). So this is not something that better framework painting behavior could fix on its own. The window has to be created differently.

* **It aligns with what the platform already does elsewhere.** Skipping the redirection surface is the standard arrangement for windows whose content is composed rather than drawn with GDI, which is exactly what a WinUI 3 window is.

### Scope

| Capability | Priority |
| :---------- | :------- |
| Apps can have their windows created without a GDI redirection surface | Must |
| The saving requires no changes to how app content is written or rendered | Must |
| The behavior is opt-in, so apps that rely on GDI painting on the window are unaffected | Must |
| The choice is discoverable and documented, including what it costs an app that opts in | Should |
| The framework's own window painting adapts, rather than silently doing nothing | Should |
| Becomes the default for new apps once the compatibility impact is understood | Could |
| The surface can be turned on or off after the window has been created | Won't |

The last row is a platform constraint rather than a design preference: see the note on creation-time behavior below.

### Important Notes

### Measurements

Windows 11 24H2 (build 26667). Each arm creates a batch of 40 identically sized top-level windows in one process, and reports the change in the compositor's GPU-committed memory divided by the number of windows, measured against the process's own idle baseline. Batching lifts the per-window cost above the noise floor. The three arms differ only in how the window is created and whether it paints.

Per-window delta in `dwm.exe` GPU-committed memory, in MB:

| window size | one BGRA bitmap | normal window | window that never paints | `WS_EX_NOREDIRECTIONBITMAP` |
| ---: | ---: | ---: | ---: | ---: |
| 1600 × 1000 | 6.10 | 6.11 | 6.11 | **0.00** |
| 1920 × 1080 | 7.91 | 7.91 | 7.91 | **0.00** |

Stable and reproducible across repeated runs. The measured cost matches one 32-bit bitmap of the window's size to within 0.01 MB, which is what identifies what is being allocated.

### Two findings worth calling out

**Not painting does not help.** The middle column above is a window with no class background brush that claims `WM_ERASEBKGND` without ever taking a device context. It never paints, and nothing ever draws into its surface. It still costs the full amount. The allocation follows from the window being redirected at all, not from anything drawing into it. This rules out the simpler theory that a framework which avoided GDI painting would avoid the cost as a side effect.

**The style is creation-time only.** Applying `WS_EX_NOREDIRECTIONBITMAP` with `SetWindowLong` after the window exists does not release the surface, and the style does not even read back as set afterwards. This is why the capability has to come from whoever creates the window, and why it cannot be exposed as a property that is toggled later.

### Interaction with DWM-drawn backdrop materials

A window with no redirection surface contributes no opaque pixels of its own. That is also the condition a DWM-drawn system backdrop material needs in order to be visible, which currently has to be arranged by other means. So this change is expected to simplify that path as well as save memory. This is a secondary benefit and would need verifying separately.

### Open Questions

* **What shape should the opt-in take?** Per window at creation, an application-wide setting, or something declared in the app's manifest? The creation-time constraint means it cannot be a property set on an existing window, which rules out the most obvious shape.

* **What exactly does an app give up?** A window without a redirection surface cannot be painted with GDI at all. The practical impact on apps that host child windows, use GDI interop, or otherwise draw on the window handle needs to be spelled out clearly, so that opting in is an informed choice.

* **What happens to the framework's own window painting?** The window background is currently filled so that the window doesn't briefly show unpainted content before the island renders its first frame. That painting has no effect on a window with no redirection surface, so the behavior at that moment needs to be defined rather than left to chance.

* **Could this eventually become the default?** If the set of affected scenarios turns out to be small and well understood, defaulting it for new apps would extend the benefit to everyone rather than only to apps that know to ask.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.