Skip to content

fix(drr): stop DRR support probe from stalling input every poll - #52

Merged
carterscode merged 1 commit into
mainfrom
fix/drr-support-probe-input-stall
Jun 20, 2026
Merged

fix(drr): stop DRR support probe from stalling input every poll#52
carterscode merged 1 commit into
mainfrom
fix/drr-support-probe-input-stall

Conversation

@carterscode

Copy link
Copy Markdown
Owner

Problem

On v0.1.56 (and earlier), the mouse and keyboard hitch about every 30 seconds while GamerGuardian runs. The v0.1.56 circuit-breaker + tiering fix did not resolve it.

Root cause (diagnosed via the live machine)

Evidence from the affected machine: the change log sat idle for 22 minutes while the hitch continued, and ~35 settings were monitored+auto-apply but nothing was being applied — so the interrupt is not the auto-apply/UAC path. It's something the poll itself does every cycle.

DrrMonitor.CheckDrift runs on every poll for every active display (the Monitor checkbox is filtered after CheckDrift, so it runs even when DRR is unmonitored — which it was). It calls DrrInterop.IsSupported, which is not a read: it flips the BOOST_REFRESH_RATE flag and calls SetDisplayConfig(…, SDC_VALIDATE | SDC_VIRTUAL_REFRESH_RATE_AWARE). On a DRR-capable high-refresh display, that display-config validation briefly re-evaluates the pipeline and stalls input — every 30s, with no log line (it's a probe, not an apply). This is the only display-config write in any check path (verified: RefreshRate/Resolution use read-only EnumDisplaySettingsEx; Hdr uses read-only DisplayConfigGetDeviceInfo).

The v0.1.56 fix didn't help because DRR is the "volatile" tier still polled every 30s, and the circuit-breaker only bounds the apply path — this is in the check path.

Fix

DRR capability is static per display (panel + driver + OS), so:

  • Cache the support probe — the SetDisplayConfig(SDC_VALIDATE) call now runs at most once per display, invalidated on a display-topology change (monitor hot-plug).
  • Skip all display-config work in DrrMonitor.CheckDrift for displays the user isn't monitoring.

Testing

  • dotnet build clean (0 warnings; TreatWarningsAsErrors).
  • dotnet test553 passed, 0 failed (4 new: probe runs once per target across many polls, value cached, ClearSupportCache re-probes, per-adapter/target isolation — via an injectable probe seam since the native call needs a real display).

Verification note

Cannot reproduce the subjective input stall in CI (needs the physical display), but the cause is established by elimination — it is the sole display-config write in the per-poll path — and the fix provably removes the per-poll SetDisplayConfig call. Confidence: High.

🤖 Generated with Claude Code

DrrInterop.IsSupported probes DRR capability by toggling the
BOOST_REFRESH_RATE flag and calling SetDisplayConfig(SDC_VALIDATE), which
on many GPU/driver combos briefly re-evaluates the display pipeline and
stalls the mouse + keyboard. DrrMonitor.CheckDrift ran this on every 30s
poll for every active display -- regardless of whether DRR was even
monitored (the IsMonitored filter is applied after CheckDrift) -- which is
the real cause of the periodic input hitch users still saw after the
v0.1.56 circuit-breaker/tiering fix (that only bounded the apply path; this
is in the check path).

DRR capability is static per display, so cache it: the SDC_VALIDATE probe
now runs at most once per display (cleared on a display-topology change),
and DrrMonitor skips all display-config work for displays the user isn't
monitoring. No log line accompanied the stall because it was a check-time
probe, not an apply -- which is why the change log looked idle.

Adds 4 caching tests via an injectable probe seam. 553 green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@carterscode
carterscode merged commit b546568 into main Jun 20, 2026
5 checks passed
@carterscode
carterscode deleted the fix/drr-support-probe-input-stall branch June 20, 2026 19:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant