From 555ec2a3b7ac92ef2868ae34e81dadfdeeccfcd3 Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Tue, 16 Jun 2026 10:44:06 +0000 Subject: [PATCH] =?UTF-8?q?Revert=20"fix(host/windows):=20rebuild=20the=20?= =?UTF-8?q?output=20fresh=20on=20every=20WGC=E2=86=94DDA=20source=20switch?= =?UTF-8?q?"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 3f191ba2ea84ce1494bbbfdd58b43c8774228e97. --- .../src/capture/composed_flip.rs | 45 +++++-------------- crates/punktfunk-host/src/m3.rs | 44 +++++++----------- 2 files changed, 27 insertions(+), 62 deletions(-) diff --git a/crates/punktfunk-host/src/capture/composed_flip.rs b/crates/punktfunk-host/src/capture/composed_flip.rs index ade20fb..6e1a3f2 100644 --- a/crates/punktfunk-host/src/capture/composed_flip.rs +++ b/crates/punktfunk-host/src/capture/composed_flip.rs @@ -17,21 +17,19 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; -use windows::core::w; +use windows::core::{w, PCWSTR}; use windows::Win32::Foundation::{HWND, LPARAM, LRESULT, WPARAM}; -use windows::Win32::Graphics::Gdi::{GetStockObject, BLACK_BRUSH, HBRUSH}; use windows::Win32::System::LibraryLoader::GetModuleHandleW; use windows::Win32::System::StationsAndDesktops::{ CloseDesktop, GetUserObjectInformationW, OpenInputDesktop, SetThreadDesktop, DESKTOP_ACCESS_FLAGS, DESKTOP_CONTROL_FLAGS, UOI_NAME, }; use windows::Win32::UI::WindowsAndMessaging::{ - CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW, GetSystemMetrics, - PeekMessageW, RegisterClassW, SetLayeredWindowAttributes, SetWindowPos, ShowWindow, - TranslateMessage, HWND_TOPMOST, LWA_COLORKEY, MSG, PM_REMOVE, SM_CXVIRTUALSCREEN, - SM_CYVIRTUALSCREEN, SM_XVIRTUALSCREEN, SM_YVIRTUALSCREEN, SWP_NOACTIVATE, SWP_NOMOVE, - SWP_NOSIZE, SW_SHOWNOACTIVATE, WNDCLASSW, WS_EX_LAYERED, WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, - WS_EX_TOPMOST, WS_EX_TRANSPARENT, WS_POPUP, + CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW, PeekMessageW, RegisterClassW, + SetLayeredWindowAttributes, SetWindowPos, ShowWindow, TranslateMessage, HWND_TOPMOST, + LWA_ALPHA, MSG, PM_REMOVE, SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOSIZE, SW_SHOWNOACTIVATE, + WNDCLASSW, WS_EX_LAYERED, WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_EX_TOPMOST, WS_EX_TRANSPARENT, + WS_POPUP, }; /// A running force-composed-flip overlay. Drop signals the thread to tear down its window + exit. @@ -107,8 +105,6 @@ unsafe fn make_overlay() -> Option { lpfnWndProc: Some(wndproc), hInstance: hinst.into(), lpszClassName: class, - // Paint the window black so LWA_COLORKEY(black) keys it out → visually invisible. - hbrBackground: HBRUSH(GetStockObject(BLACK_BRUSH).0), ..Default::default() }; let atom = RegisterClassW(&wc); @@ -119,24 +115,15 @@ unsafe fn make_overlay() -> Option { tracing::warn!(err = e.0, "force-composed-flip: RegisterClassW failed"); } } - // Cover the WHOLE virtual screen (all outputs incl. the SudoVDA): a 1x1 corner window may not even - // sit on the captured output's rect, and independent-flip is per-output. A window overlapping the - // output is what disqualifies its flip. - let (vx, vy, vw, vh) = ( - GetSystemMetrics(SM_XVIRTUALSCREEN), - GetSystemMetrics(SM_YVIRTUALSCREEN), - GetSystemMetrics(SM_CXVIRTUALSCREEN).max(1), - GetSystemMetrics(SM_CYVIRTUALSCREEN).max(1), - ); let hwnd = match CreateWindowExW( WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOPMOST | WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW, class, w!(""), WS_POPUP, - vx, - vy, - vw, - vh, + 0, + 0, + 1, + 1, None, None, Some(hinst.into()), @@ -150,16 +137,8 @@ unsafe fn make_overlay() -> Option { return None; } }; - // Color-key on black: the window is painted black (its WNDCLASS background brush) and black is keyed - // out, so it's visually invisible — but DWM counts it as a real opaque window covering the output, - // which is what disqualifies the fullscreen independent-flip (a near-zero ALPHA layered window is - // often ignored by the flip-eligibility check; a color-keyed one is not). - let _ = SetLayeredWindowAttributes( - hwnd, - windows::Win32::Foundation::COLORREF(0x0000_0000), - 0, - LWA_COLORKEY, - ); + // alpha=1: technically visible (so it disqualifies independent-flip) but imperceptible. + let _ = SetLayeredWindowAttributes(hwnd, windows::Win32::Foundation::COLORREF(0), 1, LWA_ALPHA); let _ = ShowWindow(hwnd, SW_SHOWNOACTIVATE); let _ = SetWindowPos( hwnd, diff --git a/crates/punktfunk-host/src/m3.rs b/crates/punktfunk-host/src/m3.rs index 29d646a..46aacc0 100644 --- a/crates/punktfunk-host/src/m3.rs +++ b/crates/punktfunk-host/src/m3.rs @@ -2453,40 +2453,26 @@ fn virtual_stream_relay( }, "two-process: source switch" ); - // Rebuild the SudoVDA output FRESH on every source switch — the key insight: a fresh - // reconnect captures the secure desktop but the live transition (which reused the - // session-start output, created while on the NORMAL desktop) does not. `build` does the - // exact reconnect setup: REMOVE + fresh ADD of the virtual monitor + re-isolate + a fresh - // capturer, so the new output is in the clean state that DDA can duplicate on the secure - // desktop. Drop the old DDA (it's bound to the old target); reopen on the new one. - match build(&mut vd, cur_mode) { - Ok((ka, rl, tg, hz)) => { - relay = rl; // fresh helper (drops the old) ... - _keepalive = ka; // ... then releases the old output - target = tg; - effective_hz = hz; - interval = std::time::Duration::from_secs_f64(1.0 / hz.max(1) as f64); - } - Err(e) => { - tracing::error!(error = %format!("{e:#}"), - "two-process: source-switch rebuild failed — staying on the current source"); - } - } - dda = None; // old DDA was on the old target if secure { - match open_dda(&target, cur_mode.width, cur_mode.height, effective_hz) { - Ok(mut p) => { - p.enc.request_keyframe(); - dda = Some(p); - } - Err(e) => { - tracing::error!(error = %format!("{e:#}"), - "two-process: DDA open failed — secure desktop will freeze on last frame"); + if dda.is_none() { + match open_dda(&target, cur_mode.width, cur_mode.height, effective_hz) { + Ok(p) => dda = Some(p), + Err(e) => { + tracing::error!(error = %format!("{e:#}"), + "two-process: DDA open failed — secure desktop will freeze on last frame"); + } } } + if let Some(d) = dda.as_mut() { + d.enc.request_keyframe(); + } next = std::time::Instant::now(); + } else { + // Returning to the helper: drain stale buffered AUs (encoded while we ignored it) and + // force a fresh IDR; await_idr then skips the stale deltas until that IDR arrives. + while relay.try_recv().is_ok() {} + relay.request_keyframe(); } - // (normal: the fresh helper's first frame is its opening IDR — await_idr clears on it.) } if want_kf { if secure {