Skip to content

[v3][Windows] Mixed-DPI monitor drag kills WebView2 GPU process repeatedly until the browser process exits — window permanently blank #5732

Description

@randalmurphal

Description

On a mixed-DPI multi-monitor setup, dragging a Wails v3 window from an external monitor onto the (different scale factor) laptop display makes the embedded WebView2 browser process compute a degenerate scale(0,0) transform. The viz compositor rejects the resulting frame and kills the GPU process; the kill repeats on every submitted frame until Chromium's crash limit is hit, at which point the browser process itself exits and the window is left permanently blank — every subsequent controller COM call fails with ERROR_INVALID_STATE (0x8007139F) until the app is restarted.

(Before alpha2.112 this was a hard host-process crash rather than a blank window, because transient COM errors used to reach errorCallbackos.Exit(1) — the path audited in #5580. alpha2.112 made it survivable; this issue is about the underlying WebView2 death.)

Steps to reproduce

  1. Windows machine with monitors at different scale factors (repro box: laptop display + 3 external monitors, mixed scaling, Intel iGPU).
  2. Run any Wails v3 (v3.0.0-alpha2.112) app.
  3. Drag the window across the DPI boundary onto the differently-scaled display, possibly a few times.
  4. Window renders for a moment, blanks, and never recovers (pre-alpha2.112: host app crashes).

Reproduces reliably on the affected machine; needs the mixed-DPI hardware condition.

Evidence (chrome_debug.log from the WebView2 profile, --enable-logging --v=1)

The full chain from the dying session:

[25604:7252:0703/132849.877:ERROR:ui\gfx\geometry\transform.cc:505] NOTREACHED hit. [ 0 0 0 0
  0 0 0 0
  0 0 1 0
  0 0 0 1 ]
 is not invertible
[25604:7252:0703/132851.029:ERROR:content\browser\gpu\gpu_process_host.cc:1063] GPU process exited unexpectedly: exit_code=-2147483645
[25604:7252:0703/132900.954:ERROR:ui\gfx\geometry\transform.cc:505] NOTREACHED hit. [ 0 0 0 0 ...] is not invertible
[25604:7252:0703/132901.656:ERROR:content\browser\gpu\gpu_process_host.cc:1063] GPU process exited unexpectedly: exit_code=-2147483645
[25604:7252:0703/132905.150:ERROR:ui\gfx\geometry\transform.cc:505] NOTREACHED hit. [ 0 0 0 0 ...] is not invertible
[25604:7252:0703/132905.799:ERROR:content\browser\gpu\gpu_process_host.cc:1063] GPU process exited unexpectedly: exit_code=-2147483645

When the kills come fast enough, Chromium gives up and the browser process exits:

FATAL:content\browser\gpu\gpu_data_manager_impl_private.cc GPU process isn't usable. Goodbye.

exit_code=-2147483645 is 0x80000003 (STATUS_BREAKPOINT — a CHECK kill, not a GPU driver fault). No Crashpad dumps are produced; the browser side treats it as an orderly shutdown.

Analysis

wails runs WebView2 in the go-webview2 module's raw-pixels configuration: PutBoundsMode(USE_RAW_PIXELS) + PutShouldDetectMonitorScaleChanges(false), with the host pushing PutRasterizationScale from its WM_DPICHANGED handler (webview_window_windows.go WM_DPICHANGED path).

That host-managed mode is doc-legal, but it's a path almost no WebView2 embedder exercises (mainstream hosts run DIP bounds + detection on). During a monitor cross, the host's scale/bounds writes race the browser process's own internal display bookkeeping (which keeps running even with detection off), and the browser lands on a zero x/y scale when building the compositor transform. That looks like the same underlying race as #5677's shrink-then-disappear symptom — #5677's fix (re-asserting bounds after the scale re-put) treats one observable symptom of it.

Fix, validated

Two changes, one behavioral unit — make Edge the only writer of the rasterization scale:

  1. Re-enable ShouldDetectMonitorScaleChanges (the WebView2 default) right after Embed. Bounds stay raw-pixels.
  2. Gate resyncWebviewRasterizationScale off while detection is on, so the host never writes the scale concurrently with Edge. (With both writers active, a transient NOTREACHED + one GPU kill per crossing still occurred — self-healing, but visible as a blank flash.)

Branch: https://github.com/randalmurphal/wails/tree/fix/webview2-mixed-dpi-rasterization-scale (single commit off the v3.0.0-alpha2.112 tag).

After this change the repro machine shows zero NOTREACHED / GPU-process exits across repeated boundary drags, with correct rendering at every scale factor.

Caveats stated up front, since this touches scar tissue: it flips a deliberate go-webview2 design choice, and it's validated on one machine / one WebView2 runtime (149.0.4022.98, Windows 11 26200). The #5544 / #5605 minimize-restore scenarios route around the now-dormant host resync and were not individually re-tested — with detection on, Edge's own (heavily exercised) monitor-change path handles them, and the host makes strictly fewer COM calls into possibly-suspended controllers, but maintainer judgment on that history is exactly why this is an issue with a linked branch rather than a direct PR.

Happy to submit the branch as a PR if this direction looks right to you.

Environment

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugSomething isn't workingv3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions