chore(host/windows): clean up DDA capture — fix unused imports, quiet secure-desktop log, sane retry default

- Remove 4 unused imports (PCWSTR in composed_flip, anyhow macro + SizeInt32 in
  wgc, Write in wgc_relay).
- DuplicateOutput1 retry defaults to N=1 (immediate legacy): on the secure
  desktop DuplicateOutput1 is LOGON_UI-only so it always refuses, and the
  release-before-reduplicate + gentle recovery keep the legacy dup stable;
  retrying there only blocked. Still env-tunable (PUNKTFUNK_DUP_RETRY_N/_MS).
- Throttle the 'using legacy DuplicateOutput' warning (expected + once-per-gentle-
  recovery on secure) so a lock dwell doesn't flood the log.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-16 17:05:02 +00:00
parent dc734c711b
commit f469dfcc76
4 changed files with 19 additions and 9 deletions
@@ -17,7 +17,7 @@
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use windows::core::{w, PCWSTR};
use windows::core::w;
use windows::Win32::Foundation::{HWND, LPARAM, LRESULT, WPARAM};
use windows::Win32::System::LibraryLoader::GetModuleHandleW;
use windows::Win32::System::StationsAndDesktops::{
+16 -5
View File
@@ -202,10 +202,15 @@ unsafe fn duplicate_output(
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(200);
// Default 1 (no retry → immediate legacy fallback). On the secure desktop DuplicateOutput1
// ALWAYS refuses (only LOGON_UI may use it), so retrying there just blocks the capture thread;
// and on the normal desktop the release-before-reduplicate + gentle recovery already keep the
// legacy dup stable. Raise PUNKTFUNK_DUP_RETRY_N only on a box where DuplicateOutput1 can win
// the old-dup-teardown race (then PUNKTFUNK_DUP_RETRY_MS sets the per-wait, default 200).
let attempts: u64 = std::env::var("PUNKTFUNK_DUP_RETRY_N")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(6)
.unwrap_or(1)
.max(1);
let mut last_err = None;
for attempt in 0..attempts {
@@ -225,10 +230,16 @@ unsafe fn duplicate_output(
}
}
if let Some(e) = last_err {
tracing::warn!(
error = %format!("{e:?}"),
"DuplicateOutput1 failed after retries — falling back to legacy DuplicateOutput (will churn)"
);
// Expected on the secure (Winlogon) desktop (DuplicateOutput1 is LOGON_UI-only) and fires
// once per gentle recovery there — throttle so a lock dwell doesn't flood the log. The
// legacy fallback below handles it; gentle recovery keeps it from churning.
static FALLBACKS: AtomicU64 = AtomicU64::new(0);
if FALLBACKS.fetch_add(1, Ordering::Relaxed) % 64 == 0 {
tracing::warn!(
error = %format!("{e:?}"),
"DuplicateOutput1 unavailable — using legacy DuplicateOutput (expected on the secure desktop)"
);
}
}
}
output.DuplicateOutput(device).context("DuplicateOutput")
+1 -2
View File
@@ -20,7 +20,7 @@ use super::dxgi::{
find_output, make_device, nudge_cursor_onto, D3d11Frame, HdrConverter, WinCaptureTarget,
};
use super::{CapturedFrame, Capturer, FramePayload, PixelFormat};
use anyhow::{anyhow, bail, Context, Result};
use anyhow::{bail, Context, Result};
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Arc, Condvar, Mutex};
use std::time::{Duration, Instant};
@@ -30,7 +30,6 @@ use windows::Graphics::Capture::{
Direct3D11CaptureFrame, Direct3D11CaptureFramePool, GraphicsCaptureItem, GraphicsCaptureSession,
};
use windows::Graphics::DirectX::DirectXPixelFormat;
use windows::Graphics::SizeInt32;
use windows::Win32::Foundation::{CloseHandle, HANDLE};
use windows::Win32::Graphics::Direct3D11::{
ID3D11Device, ID3D11DeviceContext, ID3D11RenderTargetView, ID3D11ShaderResourceView,
@@ -15,7 +15,7 @@
use crate::capture::dxgi::WinCaptureTarget;
use anyhow::{bail, Context, Result};
use std::io::{BufRead, BufReader, Read, Write};
use std::io::{BufRead, BufReader, Read};
use std::sync::mpsc::{Receiver, SyncSender};
use std::sync::Mutex;
use windows::core::PWSTR;