Skip to content

dp: assume sink capabilities on force-enabled connectors without DPCD#1195

Open
HarryAnkers wants to merge 1 commit into
NVIDIA:mainfrom
HarryAnkers:dp-headless-sink-caps
Open

dp: assume sink capabilities on force-enabled connectors without DPCD#1195
HarryAnkers wants to merge 1 commit into
NVIDIA:mainfrom
HarryAnkers:dp-headless-sink-caps

Conversation

@HarryAnkers

@HarryAnkers HarryAnkers commented Jun 11, 2026

Copy link
Copy Markdown

Hey I've been trying to get virtual displays working for sunshine game streaming. I really want 4k 120 to work for my MacBook Pro to stream my display. To do this and still have my tv connected I this to work on display port.
Obviously this is mostly made with the help of Claude but is tested and works. Please let's get this merged in so I can move to cachy os haha

Hers the Claude description and shout out to inspired pr and issue — #1186 (thanks @Rohithmatham12, this PR follows your approach on the DP side) and #1184:


Problem

A DisplayPort connector that is force-enabled with an EDID override (video=DP-n:e + drm.edid_firmware=...) and has no physical sink attached is capped at modes that fit the bare assumed link bandwidth — in practice 4K60 — and HDR cannot be enabled on it at all. This makes DP unusable for headless / virtual-display setups (Sunshine/Moonlight game streaming hosts and similar), where the framebuffer is consumed by a screen-capture encoder rather than a physical monitor. This is the DP side of the limitation described in #1184; #1186 addresses the HDMI FRL side.

Root cause

With no physical sink there is no HPD, so nvDpyGetDynamicData() short-circuits the force-connected case without ever notifying the DP library — no discovery runs and no device is created. Even if a long pulse is delivered, parseAndReadCaps() fails its AUX read and leaves revisionMajor = 0, which makes notifyLongPulseInternal() bail out before discovery (if (!hal->isAtLeastVersion(1, 0)) goto completed). The result is that mode validation has no sink DSC/FEC caps (so anything above the bare link rate is pruned) and nvDpyIsHDRCapable() fails its DPCD revision check (so HDR enable is rejected).

Change

Four small steps, all gated on the existing dpcdOffline state so connectors with a responsive sink take exactly the same paths as before:

  1. nvDpyGetDynamicData() — when a dpy is force-connected on a DP connector the DP library considers unplugged, simulate a long pulse so discovery runs and a device is created.
  2. DPCDHALImpl::parseAndReadCaps() — on a failed caps read, fall back to populateFakeDpcd() (previously only done on the unplug path) so discovery can proceed. The faked DPCD revision is raised from 1.1 to 1.4 since HDR requires DPRX 1.3+.
  3. DeviceImpl::getDSCSupport() / readAndParseDSCCaps() / getFECSupport() — when the AUX read fails and DPCD is offline, synthesize DSC decoder caps modeled on a typical DSC 1.2 4K high-refresh monitor, and claim FEC, so high-bandwidth modes validate through the DSC path.
  4. DPCDHALImpl::getSDPExtnForColorimetry() — claim VSC SDP colorimetry support when DPCD is offline so HDR signaling can be enabled.

Testing

RTX 3060 Ti (GA104), driver 610.43.02, kernel 7.0.11, KDE Plasma 6.6 Wayland, connector force-enabled via drm.edid_firmware=DP-2:edid/<file> video=DP-2:e with an EDID declaring 3840x2160@120:

  • Before: connector offers 3840x2160 up to 60 Hz only; HDR enable is rejected by the driver.
  • After: discovery runs (DP> HPD v1.4, DPCONN> New device | Native DSC Capability - Capable), 3840x2160@120 validates and sets (DSC Mode = SINGLE), and HDR + wide color gamut enable end to end. Verified streaming the result with Sunshine (KMS capture, HEVC Main10).
  • A physically connected DP monitor on the same GPU continues to behave normally (its DPCD reads succeed, so none of the new paths are taken).

Expected, benign noise when the mode is set: DP-DEV> Error querying DSC Enable State! — the post-modeset confirmation read has no sink to talk to.

Open questions for review

  • parseAndReadCaps() now falls back to fake caps for any failed caps read, not just user-forced connectors — the DP library has no visibility into the force-connected flag without new plumbing. The AUX read already retries 16 times before failing, and the unplug path has populated fake DPCD this way for a long time, but if you'd prefer this to be opt-in (a regkey like APPLY_MAX_LINK_RATE_OVERRIDES, or plumbing the forced flag through notifyLongPulse), happy to rework it.
  • The fake DPCD revision bump (1.1 → 1.4) also applies to the existing EDID-locked fake-device path. I didn't find anything that depends on it staying 1.1, but flagging it since that path predates this change.
  • The synthesized DSC cap values are my best reading of parseDscCaps() and the DPCD 1.4 spec; if there's a preferred canonical set for a virtual sink, glad to switch to it.

Tested in combination with #1186 (the two are independent — this touches only the DP path). Happy to rework any of the above based on feedback.

When a DP connector is force-enabled with an EDID override
(video=DP-n:e + drm.edid_firmware) and no physical sink is attached,
no HPD event ever reaches the DP library, so no device is created.
Mode validation then runs without sink DSC/FEC capabilities and HDR
support checks fail outright, capping such virtual displays at modes
that fit the bare link bandwidth (4K60) with no HDR.

Address this in four steps, all gated on the existing dpcdOffline
state so connectors with a responsive sink are unaffected:

- nvDpyGetDynamicData(): when a dpy is force-connected on a DP
  connector that the DP library considers unplugged, simulate a long
  pulse so the library performs discovery and creates a device.

- DPCDHALImpl::parseAndReadCaps(): when the caps read fails, fall
  back to populateFakeDpcd() instead of leaving revision 0, which
  previously made notifyLongPulseInternal() bail out before
  discovery. Also raise the faked DPCD revision to 1.4, since HDR
  requires DPRX 1.3+.

- DeviceImpl::getDSCSupport() / readAndParseDSCCaps() /
  getFECSupport(): when the AUX read fails and DPCD is offline,
  synthesize DSC decoder capabilities modeled on a typical DSC 1.2
  4K high-refresh monitor, and claim FEC, so high-bandwidth modes
  can validate through the DSC path.

- DPCDHALImpl::getSDPExtnForColorimetry(): claim VSC SDP colorimetry
  support when DPCD is offline so HDR signaling can be enabled.

Tested on RTX 3060 Ti (610.43.02, KDE Wayland): a force-enabled DP
connector with a 4K120 EDID now validates and sets 3840x2160@120
with DSC single mode, and HDR enables end to end.
@CLAassistant

CLAassistant commented Jun 11, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@Rohithmatham12

Copy link
Copy Markdown

Thanks for carrying the DP side forward and for testing it on the same headless streaming setup. The problem split makes sense to me: #1186 handles HDMI FRL, while this needs to make the DP DSC/HDR path usable when a connector is force-enabled but has no physical AUX/DPCD sink.

One implementation detail I would tighten before maintainer review is the scope of the fake capability fallback. The current patch makes DPCDHALImpl::parseAndReadCaps() call populateFakeDpcd() on any failed caps read. That fixes the force-enabled virtual connector case, but it also changes behavior for physical DP sinks with transient or broken AUX reads.

A safer shape would be to make the synthesized DPCD/DSC/FEC/HDR behavior explicitly virtual-sink scoped, for example:

  • add a DP-library-visible flag for "forced/offline virtual sink" when nvDpyGetDynamicData() handles pRequest->forceConnected on a DPLib connector with no plugged device;
  • only allow the parseAndReadCaps() fake-DPCD fallback and the synthetic DSC/FEC/VSC colorimetry paths when that flag is set;
  • clear the flag on a real unplug/plug transition or when DPCD reads succeed, so physical monitors with responsive AUX keep the existing behavior.

That would keep the good tested result here while matching the risk profile of #1186: default behavior unchanged, physical sink behavior unchanged, and virtual/headless behavior enabled only when the user has explicitly force-enabled the connector with an EDID override.

The reporter validation is strong. I think the main question for NVIDIA review will be whether the fake DPCD/DSC/HDR capability path is narrowly gated enough.

@Rohithmatham12

Copy link
Copy Markdown

I put together a narrower variant of this idea in #1196 that tries to address the main scoping concern: fake DPCD/DSC/FEC/HDR capabilities are only enabled when NVKMS is handling a force-connected DPLib connector with no plugged DP device.

So instead of falling back to fake DPCD caps on any failed caps read, it threads a virtual-sink fallback flag from the video=DP-*:e / EDID-override path into DPLib and gates the synthesized capabilities on that flag.

If you have time to test it on the same DP setup, the interesting result would be whether #1196 still exposes/sets 4K120 + HDR like this PR does, while keeping the behavior more narrowly scoped for maintainers.

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.

3 participants