Repository navigation
qemu: tell the guest the host display's refresh rate - #7982
Merged
Merged
Conversation
This was referenced Oct 18, 2026
Closed
dragoshont
marked this pull request as ready for review
October 18, 2026 13:04
osy
force-pushed
the
qemu/host-refresh-rate
branch
from
October 28, 2026 20:25
9876250 to
fe310a9
Compare
Contributor
|
The changes are tested on a MacBook Air (M3) running macOS 27.0.1. |
osy
force-pushed
the
qemu/host-refresh-rate
branch
2 times, most recently
from
October 28, 2026 21:03
2395b15 to
a412978
Compare
SPICE cannot report the host refresh rate to QEMU, so the EDID of every virtio GPU advertises a synthesised 75 Hz mode. Pick up a patch adding a refresh_rate property (mHz) that is used whenever the display reports none, so UTM can pass the rate itself. Drop the EDID patch that widened the range limits, put the rate in the standard timings and added a DisplayID 2.0 section. The viogpu3d driver takes the rate from the preferred timing for every mode, and hands Windows an EDID of its own, and Linux uses the preferred timing as it is, so Windows and Linux guests both resize up to 6016x3384 at 120 Hz without it. Related: utmapp#7820 Related: utmapp#7830 Assisted-by: GitHub Copilot:claude-opus-5.5 Assisted-by: Claude:claude-opus-5-5
The guest learns its refresh rate from the EDID that QEMU generates. SPICE has no field for the host rate, so with UTM every guest gets a made-up 75 Hz mode. Windows then lists only 75 Hz modes and composes at 75 Hz, so on a 60 Hz display about one frame in five is rendered and never shown, and a 120 Hz (ProMotion) display cannot be used at all. When a VM starts, ask its display delegate for the rate the display will be rendered at and pass it to virtio GPU devices with the refresh_rate property. That is the refresh rate of the screen the VM window is on at launch, capped by the FPS Limit preference, so the guest and the renderer agree. On macOS the renderer is updated too in case the window moved screens while the VM was stopped. On iPhone the renderer stays at 60 Hz unless a limit is set, so that is what the guest gets. Remote sessions have no local display and keep QEMU's default. Related: utmapp#7820 Assisted-by: GitHub Copilot:claude-opus-5.5 Assisted-by: Claude:claude-opus-5-5
osy
force-pushed
the
qemu/host-refresh-rate
branch
from
October 29, 2026 01:50
a412978 to
b652538
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Guests in UTM always get a 75 Hz display, whatever the Mac's display runs at.
QEMU only puts the host refresh rate in the guest's EDID when the display frontend reports it, and SPICE can't, so the guest gets a made-up 75 Hz mode. Windows 11 ARM64 on viogpu3d then lists only 75 Hz modes:
This passes the main screen's refresh rate to virtio GPU devices through QEMU's new
refresh_rateproperty.Depends on utmapp/qemu#7; without it QEMU rejects the argument. Related: #7820.
Testing: macOS 27.0.1, MacBook Pro M5 Max, external 60 Hz display plus the built-in 120 Hz panel. Debug build with utmapp/qemu#7, disposable Alpine VM with
virtio-gpu-gl-pci:refresh_rate=60000refresh_rate=120000Windows 11 Pro ARM64 (build 26300, viogpu3d 100.6.101.58000, D3DMetal) on the same build:
The rate comes from
NSScreen.main, the screen with the key window when the VM starts. Moving the window to another display later doesn't change it until the next start.Test setup: an ad-hoc signed build has no app group, so UTM sets no
APP_SANDBOX_GROUP_ID, Neptune can't create shared memory and Windows shows "Display output is not active". For these runs I set the group by hand; release builds aren't affected.An AI agent ran these tests on my Mac.
I have read the AI contribution guidelines and have followed them to the best of my ability.