Skip to content

Restart Chromium when a headful display change only changes the refresh rate - #497

Open
masnwilliams wants to merge 1 commit into
mainfrom
hypeship/restart-chromium-on-refresh-change
Open

masnwilliams wants to merge 1 commit into
mainfrom
hypeship/restart-chromium-on-refresh-change

Conversation

@masnwilliams

@masnwilliams masnwilliams commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Summary

On headful images, a PATCH /display (or a /chromium/configure display part) that changes only the refresh rate at the current resolution switches the X mode but leaves Chromium rendering at its old rate. For example, 1920x1080@25 → 1920x1080@60 responds refresh_rate: 60 and xrandr reports 1920x1080 59.96*, but requestAnimationFrame keeps firing every 40ms until Chromium restarts.

Chromium on Linux re-reads the screen's refresh rate when the X screen size changes. A rate-only mode switch produces no display-metrics change, because DisplayChangeNotifier only flags DISPLAY_METRIC_REFRESH_RATE on macOS (ui/display/display_change_notifier.cc). Before #262 the Xorg path restarted Chromium after every resize, which hid this. #262 removed that restart for size changes, which Chromium handles live, so rate-only changes regressed.

Change

patchDisplayLocked (Xorg branch) now restarts Chromium with restartChromiumAndWait (which waits for DevTools to be ready) only when the realized X root size is unchanged and the refresh rate changed. The decision lives in chromiumRestartForDisplayChange:

change restart?
rate only, same size (25→60 or 60→25) yes
size only no (#262 fast path kept)
size and rate no; Chromium picks up the new rate with the size change
no change no (unchanged early return)
rate only, restart_chromium: false no; logs a warning that Chromium keeps its previous rate
  • Sizes are compared after applyResolutionAndConverge, because libxcvt rounding can map a different requested size onto the current one.
  • When Chromium is restarted, the CDP maximize re-assert is skipped (Chromium relaunches maximized). A failed restart returns a 500.
  • restart_chromium unset or true allows the restart. An explicit false opts out, which is the only way to keep the old no-restart behavior for a rate-only change.

/chromium/configure needs no change:

  • The live path reaches patchDisplayLocked, so create, pool acquire and browser update get the fix, with at most one restart per configure.
  • The restart path already applies the display while Chromium is stopped.

Cost

A rate-only change now takes about 1s inside the VM: PATCH /display measured 0.63–1.71s, median 0.97s, across 3 browsers. Size-only changes stay at 8–32ms.

The restart drops CDP connections and resets page state. That was already true of every headful resize before #262, but it now applies only to rate-only changes.

Testing

  • Unit tests: TestChromiumRestartForDisplayChange covers rate up, rate down, size only, size and rate, no change, and both restart_chromium values. go test ./cmd/api/... passes.
  • Live A/B: swapped only the kernel-images-api binary inside 3 headful browsers, built from the current release source with and without this patch, then drove the public browser update API. Values are the requestAnimationFrame median and whether Chromium restarted (PID change):
step without patch with patch
start 1920x1080@25 40ms 40ms
rate only → 1920x1080@60 40ms, no restart 16.7ms, restarted
rate only → 1920x1080@25 40ms (by luck: Chromium never left 25) 40ms, restarted
size only → 1280x800@25 40.1ms, no restart 40.1ms, no restart
size and rate → 1920x1080@60 16.7ms, no restart 16.7ms, no restart
no change 16.7ms 16.7ms, no restart
rate only → @25 with restart_chromium: false (in-VM call) — stays 16.7ms, no restart, warning logged
  • Not done: I didn't build the full image locally. The live A/B ran the real release image with only this binary changed.

Notes

The OpenAPI description of restart_chromium ("restart after resolution change ... default false for headful") is left as is. Updating it means regenerating oapi.go; I can do that in a follow-up if preferred.


Note

Medium Risk
Changes headful display handling by conditionally restarting Chromium (~1s, drops CDP/page state), but logic is narrow, tested, and opt-out via restart_chromium.

Overview
Fixes a regression where headful PATCH /display could switch the X mode to a new refresh rate while Chromium kept its old requestAnimationFrame interval, because Linux Chromium only re-reads refresh rate when the screen size changes.

After Xorg resize converges, chromiumRestartForDisplayChange decides whether to restartChromiumAndWait: yes for rate-only at the same realized resolution; no for size-only or size+rate (live resize path preserved). On restart, the CDP maximize re-assert is skipped; a failed restart surfaces as 500. Explicit restart_chromium: false skips the restart and logs a warning that the old rate persists.

TestChromiumRestartForDisplayChange covers the decision matrix and both restart_chromium values.

Reviewed by Cursor Bugbot for commit 0dd916f. Bugbot is set up for automated code reviews on this repo. Configure here.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant