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::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
use windows::core::{w, PCWSTR}; use windows::core::w;
use windows::Win32::Foundation::{HWND, LPARAM, LRESULT, WPARAM}; use windows::Win32::Foundation::{HWND, LPARAM, LRESULT, WPARAM};
use windows::Win32::System::LibraryLoader::GetModuleHandleW; use windows::Win32::System::LibraryLoader::GetModuleHandleW;
use windows::Win32::System::StationsAndDesktops::{ use windows::Win32::System::StationsAndDesktops::{
+16 -5
View File
@@ -202,10 +202,15 @@ unsafe fn duplicate_output(
.ok() .ok()
.and_then(|s| s.parse().ok()) .and_then(|s| s.parse().ok())
.unwrap_or(200); .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") let attempts: u64 = std::env::var("PUNKTFUNK_DUP_RETRY_N")
.ok() .ok()
.and_then(|s| s.parse().ok()) .and_then(|s| s.parse().ok())
.unwrap_or(6) .unwrap_or(1)
.max(1); .max(1);
let mut last_err = None; let mut last_err = None;
for attempt in 0..attempts { for attempt in 0..attempts {
@@ -225,10 +230,16 @@ unsafe fn duplicate_output(
} }
} }
if let Some(e) = last_err { if let Some(e) = last_err {
tracing::warn!( // Expected on the secure (Winlogon) desktop (DuplicateOutput1 is LOGON_UI-only) and fires
error = %format!("{e:?}"), // once per gentle recovery there — throttle so a lock dwell doesn't flood the log. The
"DuplicateOutput1 failed after retries — falling back to legacy DuplicateOutput (will churn)" // 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") 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, find_output, make_device, nudge_cursor_onto, D3d11Frame, HdrConverter, WinCaptureTarget,
}; };
use super::{CapturedFrame, Capturer, FramePayload, PixelFormat}; 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::atomic::{AtomicU64, Ordering};
use std::sync::{Arc, Condvar, Mutex}; use std::sync::{Arc, Condvar, Mutex};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
@@ -30,7 +30,6 @@ use windows::Graphics::Capture::{
Direct3D11CaptureFrame, Direct3D11CaptureFramePool, GraphicsCaptureItem, GraphicsCaptureSession, Direct3D11CaptureFrame, Direct3D11CaptureFramePool, GraphicsCaptureItem, GraphicsCaptureSession,
}; };
use windows::Graphics::DirectX::DirectXPixelFormat; use windows::Graphics::DirectX::DirectXPixelFormat;
use windows::Graphics::SizeInt32;
use windows::Win32::Foundation::{CloseHandle, HANDLE}; use windows::Win32::Foundation::{CloseHandle, HANDLE};
use windows::Win32::Graphics::Direct3D11::{ use windows::Win32::Graphics::Direct3D11::{
ID3D11Device, ID3D11DeviceContext, ID3D11RenderTargetView, ID3D11ShaderResourceView, ID3D11Device, ID3D11DeviceContext, ID3D11RenderTargetView, ID3D11ShaderResourceView,
@@ -15,7 +15,7 @@
use crate::capture::dxgi::WinCaptureTarget; use crate::capture::dxgi::WinCaptureTarget;
use anyhow::{bail, Context, Result}; 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::mpsc::{Receiver, SyncSender};
use std::sync::Mutex; use std::sync::Mutex;
use windows::core::PWSTR; use windows::core::PWSTR;