Goal: a completely headless Linux box that presents a virtual display and streams 4K 120Hz HDR to a Mac/iPad over Sunshine → Moonlight, with nothing physically plugged into the GPU. This is a running log of how far that gets on current NVIDIA + KDE Wayland, what works, and exactly where it hits a wall.
TL;DR: HDR works. 4K60 works. Arbitrary native resolutions work. 120Hz does not — the NVIDIA driver refuses to bring up HDMI 2.1 FRL (or DP DSC) on a force-enabled connector that has no real sink doing the link handshake, so anything needing more than ~600 MHz TMDS (i.e. 4K120) gets pruned to 4K60. Filed upstream at NVIDIA/open-gpu-kernel-modules#1184.
- GPU: RTX 3060 Ti (Ampere / GA104)
- Driver:
nvidia-open610.43.02 - OS: CachyOS, kernel 7.0.11-cachyos
- Desktop: KDE Plasma 6.6 on Wayland
- Streaming: Sunshine 2026.516.143833 → Moonlight (Mac / iPad)
- No monitor attached — the target is a headless streaming host.
A connector is force-enabled at boot with a custom EDID baked into the initramfs, via the
kernel drm.edid_firmware mechanism (no dummy plug, no write-protected hacks):
# /etc/default/limine (Limine cmdline)
KERNEL_CMDLINE[default]+=" drm.edid_firmware=HDMI-A-1:edid/macipad-hdr.bin video=HDMI-A-1:e"
# /etc/mkinitcpio.conf — EDID must be bundled into the initramfs
FILES=(/usr/lib/firmware/edid/macipad-hdr.bin)
Then sudo limine-update && sudo mkinitcpio -P && reboot. The connector comes up
connected with the modes the EDID advertises, even with nothing plugged in.
Sunshine captures it via the KMS (DRM) backend and encodes HEVC Main10 for HDR.
HDR is toggled at stream start with kscreen-doctor output.HDMI-A-1.hdr.enable.
- HDR end to end.
kscreen-doctor output.HDMI-A-1.hdr.enablesucceeds and Sunshine encodes true HDR:Color coding: HDR (Rec. 2020 + SMPTE 2084 PQ). Confirmed on the Mac. - 4K60 HDR (3840×2160 @ 60, 10-bit, BT.2020 + PQ).
- Arbitrary native client resolutions. Injected as detailed timings into the EDID so the
host framebuffer is pixel-perfect for the client:
3024×1890 @ 60(MacBook Pro 14", below-notch area) — HDR ✅2752×2064 @ 60(iPad Pro M4 13") — HDR ✅
HDR is rejected unless both are true:
- The connector is HDMI. DisplayPort virtual connectors reject HDR enable outright
(
applying config failed! The driver rejected the output configuration). - The EDID is real / well-formed enough. A hand-built synthetic EDID is rejected for HDR even on HDMI. A dumped real-monitor EDID (here an AOC unit with proper HDR Static Metadata + HDMI Forum VSDB + BT2020 colorimetry blocks) is accepted.
So the driver does honor HDR signaling on a sink-less connector — it just demands the sink descriptor look genuine.
No matter what the EDID declares, the force-enabled connector caps at 4K60. 4K120 needs HDMI 2.1 FRL (up to 48 Gbps) or DP DSC, and the driver won't bring either up without a real sink completing the SCDC (HDMI) / DPCD (DP) link-training handshake.
This also caps the custom native modes at 60Hz: 3024×1890 / 2752×2064 @ 120 would need ~740 MHz pixel clock, over the TMDS ceiling, so they hit the same wall and prune to 60.
Fed the connector an EDID declaring Max_FRL_Rate = 6 (48 Gbps) with VIC 118 (3840×2160@120)
in the normal RGB video data block. edid-decode validates it clean, and the kernel reads
the FRL declaration back correctly:
$ cat /sys/class/drm/card1-HDMI-A-1/edid | edid-decode
...
Maximum TMDS Character Rate: 600 MHz
Max Fixed Rate Link: 3 and 6 Gbps per lane on 3 lanes, 6, 8, 10 and 12 Gbps on 4 lanes
Despite reading that, the driver only ever offers 3840x2160@50/59/60 and prunes 4K120. So
it is not a malformed-EDID problem — the driver sees the FRL capability and still refuses
to bring up the high-bandwidth link because nothing is physically attached to negotiate it.
gamescope --backend headlessrenders 4K120 and HDR fine with no connector involved at all — so the GPU and NVENC can clearly do it.- amdgpu does not impose this restriction on virtual displays.
It is specific to NVIDIA's connector-mode validation on a sink-less output.
Tried bypassing KMS by rendering into a headless gamescope and capturing that instead.
Doesn't work with Sunshine: Sunshine's wlroots/KWin capture paths need
zwlr_screencopy_manager_v1 + zxdg_output_manager_v1, and headless gamescope exposes
neither — only gamescope_pipewire. Bridging that is real feature work, not a config.
To add native client resolutions without breaking HDR: take a real HDR monitor EDID and overwrite its unused Dummy Descriptor slots in the base block with CVT reduced-blanking detailed timings, then fix only the base-block checksum. The CTA-861 extension (HDR static metadata, HDMI Forum VSDB, BT2020) is left byte-for-byte intact, so HDR keeps working.
# CVT reduced-blanking modelines used (≈371 MHz, safely under the TMDS ceiling):
3024x1890R 371.25 3024 3072 3104 3184 1890 1893 1899 1944 +hsync -vsync
2752x2064R 370.75 2752 2800 2832 2912 2064 2067 2071 2123 +hsync -vsync
Result (edid-decode of the patched EDID):
DTD 1: 1920x1080 60.00 Hz (preferred)
DTD 2: 3024x1890 59.98 Hz 371.25 MHz <- injected
DTD 3: 2752x2064 59.97 Hz 370.75 MHz <- injected
...HDR Static Metadata: SMPTE ST2084, Hybrid Log-Gamma
...Colorimetry: BT2020RGB
For headless / virtual-display streaming: let the driver honor an EDID-declared FRL/DSC capability on a force-enabled connector, or expose a way to set the virtual connector's max link rate. Right now the only route to 4K120 is to physically plug a real 4K120 display in — which defeats the entire point of a headless streaming box.
- 4K120 / FRL blocker: NVIDIA/open-gpu-kernel-modules#1184
- Related HDR-properties issue (now resolved on 610): NVIDIA/open-gpu-kernel-modules#1101
Great write-up, @HarryAnkers! I also stream to an OLED iPad Pro so am keen to see this issue progress to eventually enable HDR 4K120 on Linux. I've not even been successful with this with a physical display connected (re your other gist).