fix(drr): stop DRR support probe from stalling input every poll - #52
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.CheckDriftruns on every poll for every active display (theMonitorcheckbox is filtered afterCheckDrift, so it runs even when DRR is unmonitored — which it was). It callsDrrInterop.IsSupported, which is not a read: it flips theBOOST_REFRESH_RATEflag and callsSetDisplayConfig(…, 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/Resolutionuse read-onlyEnumDisplaySettingsEx;Hdruses read-onlyDisplayConfigGetDeviceInfo).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:
SetDisplayConfig(SDC_VALIDATE)call now runs at most once per display, invalidated on a display-topology change (monitor hot-plug).DrrMonitor.CheckDriftfor displays the user isn't monitoring.Testing
dotnet buildclean (0 warnings;TreatWarningsAsErrors).dotnet test— 553 passed, 0 failed (4 new: probe runs once per target across many polls, value cached,ClearSupportCachere-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
SetDisplayConfigcall. Confidence: High.🤖 Generated with Claude Code