fix(host/windows): WGC relay — don't force HDR on SDR sessions across the secure mux

Re-enabling the WGC relay brought back a broken image on the secure->normal
switch. Log root cause: on returning to the normal desktop the relay called
set_advanced_color(target, true) to 'restore HDR', so the rebuilt WGC helper
captured HDR FP16 BT.2020 PQ while the session encoder is 8-bit SDR -> format
mismatch (the 'HDR gets restored when flipping back to WGC' bug).

Gate BOTH set_advanced_color toggles on bit_depth>=10. An SDR (8-bit) session
now stays SDR across WGC<->DDA switches (no HDR force, no needless topology
change); HDR sessions keep the drop-on-secure / restore-on-normal behavior.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-16 17:13:02 +00:00
parent f469dfcc76
commit d2e536d299
+14 -7
View File
@@ -2541,17 +2541,20 @@ fn virtual_stream_relay(
"two-process: source switch" "two-process: source switch"
); );
if secure { if secure {
// SDR-while-secure: drop the SudoVDA out of HDR so the secure (Winlogon) desktop // SDR-while-secure (HDR sessions ONLY): drop the SudoVDA out of HDR so the secure
// renders SDR/composed — the HDR fullscreen independent-flip is what made DDA storm // (Winlogon) desktop renders SDR/composed — HDR fullscreen independent-flip is what made
// ACCESS_LOST (black). Give the reconfig a moment to settle, then (re)open DDA fresh on // DDA storm ACCESS_LOST (black). For an SDR (8-bit) session the output is already SDR, so
// the now-SDR output. // toggling is a needless topology change AND its matching restore on the way back would
// force the desktop into HDR the 8-bit encoder can't take (broken image).
if bit_depth >= 10 {
let toggled = unsafe { let toggled = unsafe {
crate::vdisplay::sudovda::set_advanced_color(target.target_id, false) crate::vdisplay::sudovda::set_advanced_color(target.target_id, false)
}; };
if toggled { if toggled {
std::thread::sleep(std::time::Duration::from_millis(250)); std::thread::sleep(std::time::Duration::from_millis(250));
} }
dda = None; // reopen so we capture the post-toggle (SDR) output }
dda = None; // reopen so we capture the (SDR) output
match open_dda(&target, cur_mode.width, cur_mode.height, effective_hz) { match open_dda(&target, cur_mode.width, cur_mode.height, effective_hz) {
Ok(mut p) => { Ok(mut p) => {
p.enc.request_keyframe(); p.enc.request_keyframe();
@@ -2564,11 +2567,15 @@ fn virtual_stream_relay(
} }
next = std::time::Instant::now(); next = std::time::Instant::now();
} else { } else {
// Returning to the normal desktop: restore HDR on the SudoVDA (WGC captures it HDR), then // Returning to the normal desktop: restore HDR on the SudoVDA (HDR sessions ONLY — WGC
// rebuild the helper fresh so its WGC re-detects the restored colorspace, and resume. // 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).
if bit_depth >= 10 {
unsafe { unsafe {
crate::vdisplay::sudovda::set_advanced_color(target.target_id, true); crate::vdisplay::sudovda::set_advanced_color(target.target_id, true);
} }
}
dda = None; // free the secure DDA encoder dda = None; // free the secure DDA encoder
match build(&mut vd, cur_mode) { match build(&mut vd, cur_mode) {
Ok((ka, rl, tg, hz)) => { Ok((ka, rl, tg, hz)) => {