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:
@@ -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::{
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user