feat(capture/windows): the stall micro-probes get an off switch, the depth pin a backoff

Two standing costs from the interval-stutter investigation, consolidated:

- PUNKTFUNK_STALL_PROBES=0 now opts a box out of the micro-probe engine
  (per-GPU 10 Hz fence copies, a parked blocking-DwmFlush waiter, the
  5 ms-cadence CPU sentinel). Default stays ON while the field program
  runs; off, stall lines keep the driver telemetry and the cheap ETW
  present/queue discriminator and only lose the corroborating probe legs
  — the verdict matrix already treats an absent probe window honestly.

- The negotiated-depth pin-back stops hammering a display that refuses
  the flip: it was 4 CCD writes + 8 display-config queries per second,
  forever, all on the session-global display-config lock. After ~2 s of
  eager retries it re-attempts every ~4 s — still self-healing, without
  the drumbeat.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-30 23:35:32 +02:00
co-authored by Claude Fable 5
parent ecb3d1ab22
commit 789dafc95f
3 changed files with 89 additions and 37 deletions
+75 -36
View File
@@ -429,6 +429,11 @@ pub struct IddPushCapturer {
/// One-shot latch for [`Self::poll_display_hdr`]'s "could not pin the negotiated depth" error —
/// the poller samples every ~250 ms, and a display that refuses the flip refuses it every time.
hdr_pin_warned: bool,
/// Consecutive failed depth-pin attempts ([`Self::poll_display_hdr`]) — past
/// [`Self::HDR_PIN_EAGER`] the re-pin backs off to every [`Self::HDR_PIN_RETRY_EVERY`]th
/// descriptor sample: a display that refuses the flip was costing 4 CCD writes + 8 display-
/// config queries per second, forever, all on the session-global display-config lock.
hdr_pin_failures: u32,
/// The session negotiated full-chroma 4:4:4: while the display is SDR the BGRA slot passes
/// THROUGH (a plain copy into the out ring, no NV12 VideoConverter) so NVENC gets full-chroma
/// RGB and CSCs to 4:4:4 itself — measured on-glass: `chromaFormatIDC=3` + ARGB input yields
@@ -496,8 +501,11 @@ pub struct IddPushCapturer {
offered_at_fresh: u64,
max_hb_age_us: u64,
/// The Phase A.2 micro-probe engine (refcounted process singleton) — its window read rides
/// every stall report so the verdict matrix can name the disturbance class.
probes: Arc<probes::ProbeEngine>,
/// every stall report so the verdict matrix can name the disturbance class. `None` when
/// `PUNKTFUNK_STALL_PROBES=0` opted the box out (the engine costs standing threads); the
/// verdict matrix already treats an absent probe window as never-stalled, so reports just
/// lose the corroborating legs, never invent them.
probes: Option<Arc<probes::ProbeEngine>>,
/// The Phase A.3 DxgKrnl ETW watch; `None` when the session can't start (non-admin dev run)
/// — reports then say `etw=unavailable`.
etw: Option<Arc<dxgkrnl_etw::EtwWatch>>,
@@ -539,6 +547,13 @@ pub struct IddPushCapturer {
unsafe impl Send for IddPushCapturer {}
impl IddPushCapturer {
/// Failed depth-pin attempts before [`Self::poll_display_hdr`] backs its re-pin off
/// (≈2 s of eager retries at the descriptor poller's 4 Hz).
const HDR_PIN_EAGER: u32 = 8;
/// While backed off, re-attempt the depth pin on every this-many-th descriptor sample
/// (~4 s at 4 Hz) — self-healing without the 4 Hz CCD-write drumbeat.
const HDR_PIN_RETRY_EVERY: u64 = 16;
#[inline]
fn latest(&self) -> u64 {
// SAFETY: `self.header` is the live, owned shared-header mapping (page-aligned, sized for a
@@ -832,40 +847,63 @@ impl IddPushCapturer {
// either direction (its encoder re-inits on the depth change).
if (self.pyrowave || !self.client_10bit) && now.hdr != self.client_10bit {
let want = self.client_10bit;
// OBSERVE the flip; never assert it. This used to discard `set_advanced_color`'s `bool`
// and then write `now.hdr = self.client_10bit` — substituting the DESIRED state for the
// observed one, which broke in both directions on a display that cannot be flipped
// (the state this file already logs as "Downgrade point D" at open):
// - want HDR, display stays SDR: the fabricated `true` differed from `current`, so two
// samples drove `recreate_ring(true, …)` and rebuilt the ring FP16 while the driver
// composed 8-bit BGRA. Every publish was then dropped by the driver's format guard,
// `recovering_since` expired, and `try_consume` bailed — a permanent 3-second
// reconnect loop.
// - want SDR, display stays HDR: the fabricated `false` MATCHED `current`, so no
// recreate ever fired and the ring stayed BGRA against an FP16 composition. Same
// dropped-publish outcome, silently.
// Reading back immediately can catch a flip that has not settled yet; that costs one
// debounce cycle (the poller re-samples in ~250 ms) and never a wrong ring, which is why
// this does not block the frame path on a settle poll the way `open_on` does.
let requested = pf_win_display::win_display::set_advanced_color(self.target_id, want);
let observed = pf_win_display::win_display::advanced_color_enabled(self.target_id);
// A failed READ is not evidence of a failed flip — keep the poller's sample then.
now.hdr = observed.unwrap_or(now.hdr);
if now.hdr != want && !self.hdr_pin_warned {
self.hdr_pin_warned = true;
tracing::error!(
target_id = self.target_id,
want_hdr = want,
observed_hdr = ?observed,
set_advanced_color_returned = requested,
pyrowave = self.pyrowave,
client_10bit = self.client_10bit,
"IDD push: could not pin the display to the NEGOTIATED depth — following what \
it actually composes instead (a physical display forcing HDR, or a driver that \
refuses the flip). The stream's depth will not match the negotiation; the \
encoder's caps cross-check reports the truth to the client"
);
// A display that refuses the pin refuses it on every 250 ms sample — past
// [`Self::HDR_PIN_EAGER`] consecutive failures the write+read-back re-fires only on
// every [`Self::HDR_PIN_RETRY_EVERY`]th sample (~4 s), instead of 4 CCD writes +
// 8 display-config queries per second forever, all on the session-global
// display-config lock. Skipped samples keep the poller's own advanced-color read,
// so nothing is fabricated and a display that becomes flippable is re-pinned on
// the next retry sample.
if self.hdr_pin_failures < Self::HDR_PIN_EAGER
|| self.desc_seq % Self::HDR_PIN_RETRY_EVERY == 0
{
// OBSERVE the flip; never assert it. This used to discard `set_advanced_color`'s
// `bool` and then write `now.hdr = self.client_10bit` — substituting the DESIRED
// state for the observed one, which broke in both directions on a display that
// cannot be flipped (the state this file already logs as "Downgrade point D" at
// open):
// - want HDR, display stays SDR: the fabricated `true` differed from `current`,
// so two samples drove `recreate_ring(true, …)` and rebuilt the ring FP16
// while the driver composed 8-bit BGRA. Every publish was then dropped by the
// driver's format guard, `recovering_since` expired, and `try_consume`
// bailed — a permanent 3-second reconnect loop.
// - want SDR, display stays HDR: the fabricated `false` MATCHED `current`, so no
// recreate ever fired and the ring stayed BGRA against an FP16 composition.
// Same dropped-publish outcome, silently.
// Reading back immediately can catch a flip that has not settled yet; that costs
// one debounce cycle (the poller re-samples in ~250 ms) and never a wrong ring,
// which is why this does not block the frame path on a settle poll the way
// `open_on` does.
let requested =
pf_win_display::win_display::set_advanced_color(self.target_id, want);
let observed = pf_win_display::win_display::advanced_color_enabled(self.target_id);
// A failed READ is not evidence of a failed flip — keep the poller's sample then.
now.hdr = observed.unwrap_or(now.hdr);
if now.hdr != want {
self.hdr_pin_failures = self.hdr_pin_failures.saturating_add(1);
if !self.hdr_pin_warned {
self.hdr_pin_warned = true;
tracing::error!(
target_id = self.target_id,
want_hdr = want,
observed_hdr = ?observed,
set_advanced_color_returned = requested,
pyrowave = self.pyrowave,
client_10bit = self.client_10bit,
"IDD push: could not pin the display to the NEGOTIATED depth — following what \
it actually composes instead (a physical display forcing HDR, or a driver that \
refuses the flip). The stream's depth will not match the negotiation; the \
encoder's caps cross-check reports the truth to the client"
);
}
} else {
self.hdr_pin_failures = 0;
}
}
} else {
// No mismatch (or the session follows flips): the pin is healthy — a later refusal
// starts its eager attempts fresh.
self.hdr_pin_failures = 0;
}
let current = DisplayDescriptor {
hdr: self.display_hdr,
@@ -1613,7 +1651,8 @@ impl IddPushCapturer {
// uses (the gap plus a lead-in for the disturbance that CAUSED it).
probes: now
.checked_sub(stall.gap + Duration::from_millis(300))
.map(|from| self.probes.window(from, now)),
.zip(self.probes.as_deref())
.map(|(from, p)| p.window(from, now)),
etw: self.etw.as_ref().and_then(|w| {
now.checked_sub(stall.gap + Duration::from_millis(300))
.map(|from| w.summary(from, now))
@@ -610,6 +610,7 @@ impl IddPushCapturer {
client_10bit,
display_hdr,
hdr_pin_warned: false,
hdr_pin_failures: 0,
want_444,
pyrowave,
pyro_fence: None,
@@ -635,7 +636,9 @@ impl IddPushCapturer {
stall_watch: StallWatch::new(),
offered_at_fresh: 0,
max_hb_age_us: 0,
probes: super::probes::acquire(),
probes: pf_host_config::config()
.stall_probes
.then(super::probes::acquire),
etw: super::dxgkrnl_etw::acquire(),
out_ring: Vec::new(),
out_idx: 0,
+10
View File
@@ -120,6 +120,14 @@ pub struct HostConfig {
/// backend (the legacy SudoVDA backend was removed), so this is currently informational — kept for the
/// shipped `host.env` and as a forward seam if a second backend is ever added.
pub vdisplay: Option<String>,
/// `PUNKTFUNK_STALL_PROBES` — run the Windows IDD-push capture's micro-probe engine (per-GPU
/// fence probes, DWM tick/flush watchdogs, scanline + CPU sentinels — `idd_push/probes.rs`),
/// the corroborating evidence legs on every stall report. Default ON while the
/// interval-stutter field program runs; explicit-off grammar for perf-sensitive boxes — the
/// engine costs standing threads (a blocking `DwmFlush` waiter, ~10 Hz fence copies per GPU,
/// a 5 ms-cadence CPU sentinel). Off, stall lines still carry the driver telemetry + the ETW
/// present/queue discriminator (cheap, session-filtered); only the probe legs read absent.
pub stall_probes: bool,
/// `PUNKTFUNK_GAMESCOPE_STEAM` — force the bare headless gamescope spawn into its Steam
/// integration mode (`--steam`) for EVERY launch. A Steam title auto-enables `--steam` on its
/// own regardless of this knob; it exists to force it on for non-Steam launches too. Managed
@@ -235,6 +243,8 @@ impl HostConfig {
// per-session switch; see the field doc).
chacha20: env_on("PUNKTFUNK_CHACHA20").unwrap_or(true),
perf: flag("PUNKTFUNK_PERF"),
// Default ON while the interval-stutter field program runs (see the field doc).
stall_probes: env_on("PUNKTFUNK_STALL_PROBES").unwrap_or(true),
video_source: val("PUNKTFUNK_VIDEO_SOURCE"),
// Trimmed + emptied-to-None: `PUNKTFUNK_CAPTURE_MONITOR=` in a host.env means "not
// set", not "match the monitor named empty string".