fix(host/windows): WGC mux — reuse the SudoVDA monitor + helper across secure switches (no teardown/recreate)

User: re-adding WGC brought back the teardown/recreate bug (audible disconnect/
connect on the secure<->normal switch). Cause: the secure->normal switch called
build() = vd.create() = IOCTL_REMOVE old SudoVDA monitor + IOCTL_ADD new one +
respawn the helper — the same teardown/recreate kernel stress we just eliminated
from DDA, now on the mux path.

Apply the same learning (reuse, don't tear down): the SudoVDA monitor and WGC
helper persist for the whole session; only the host-DDA leg opens (on secure)
and closes (on normal). On returning to normal, RESUME the still-alive helper
(drain its secure-dwell backlog + request a keyframe) instead of rebuilding.
The HDR-session colorspace restore (set_advanced_color(true) + helper rebuild)
is kept ONLY for bit_depth>=10 — an SDR session never changed the colorspace, so
it needs no rebuild at all. The secure switch already reuses the monitor
(open_dda on the existing target).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-16 17:27:50 +00:00
parent e8d885fb4f
commit ca375c7ce8
+14 -6
View File
@@ -2581,16 +2581,22 @@ fn virtual_stream_relay(
}
next = std::time::Instant::now();
} else {
// Returning to the normal desktop: restore HDR on the SudoVDA (HDR sessions ONLY — WGC
// then captures it HDR). An SDR (8-bit) session must stay SDR; forcing HDR here is what
// made the rebuilt WGC helper capture HDR FP16 BT.2020 while the encoder is 8-bit SDR →
// format mismatch / broken image (the "HDR gets restored when flipping back" bug).
// Returning to the normal desktop: RESUME from the still-alive WGC helper. Do NOT
// recreate the SudoVDA monitor or respawn the helper — build()'s vd.create() is an
// IOCTL_REMOVE+ADD of the monitor (the audible disconnect/connect chime + the
// teardown/recreate kernel stress that broke DDA, now applied to the mux). The monitor +
// helper persist for the WHOLE session; only the host-DDA leg opens (secure) and closes
// (normal). Apply the DDA learning here: reuse, don't tear down.
dda = None; // free the secure DDA encoder; the relay (helper) is the source again
while relay.try_recv().is_ok() {} // drop secure-dwell backlog
relay.request_keyframe(); // client decoder resumes on the helper's next IDR
if bit_depth >= 10 {
// HDR session ONLY: the secure switch dropped the SudoVDA to SDR for the DDA leg, so
// here we must restore HDR AND rebuild the helper so WGC re-detects the HDR
// colorspace. An SDR session never changed the colorspace → no rebuild, no recreate.
unsafe {
crate::vdisplay::sudovda::set_advanced_color(target.target_id, true);
}
}
dda = None; // free the secure DDA encoder
match build(&mut vd, cur_mode) {
Ok((ka, rl, tg, hz)) => {
relay = rl;
@@ -2607,6 +2613,8 @@ fn virtual_stream_relay(
}
}
}
next = std::time::Instant::now();
}
}
if want_kf {
if secure {