[PowerDisplay] Detect built-in panel when driven by the discrete GPU#48637
[PowerDisplay] Detect built-in panel when driven by the discrete GPU#48637moooyo wants to merge 3 commits into
Conversation
Classify displays by capability instead of nominal OutputTechnology. WMI discovery now runs first over the full QueryDisplayConfig inventory; every panel WmiMonitorBrightness exposes is treated as internal, and whatever WMI does not claim is routed to DDC/CI. This fixes the built-in panel being dropped on dual-GPU laptops: when the discrete GPU drives the eDP panel, Windows reports its OutputTechnology as DisplayPort-External (10), so the strict OutputTechnology -> DDC-only routing introduced in #47740 sent the panel to DDC/CI (which an eDP panel does not speak) and PowerDisplay reported "can't detect the display". WmiMonitorBrightness still exposes that panel regardless of which GPU drives it, so capability-based routing finds it. - Add MonitorIdentity.FromInstanceName: reduce a WMI InstanceName to the same canonical Monitor.Id as FromDevicePath; remove the separate PnpHardwareKey. - WmiController matches WmiMonitorBrightness against the full inventory by Monitor.Id; the persisted Id is still taken from the matched DevicePath so it stays byte-identical to the DDC route and to prior releases. - MonitorManager runs WMI first, treats WMI-claimed displays as internal, sends the remainder to DDC/CI. - Delete DisplayClassifier and MonitorDisplayInfo.IsInternal. Accepted trade-off: a monitor exposing both WMI brightness and DDC/CI is controlled via WMI only and does not get DDC-only features. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| // reported by QueryDisplayConfig as DisplayPort-External, yet WmiMonitorBrightness | ||
| // still exposes it. The InstanceName and DevicePath captured in that state must reduce | ||
| // to the same Monitor.Id so WMI can claim the panel and brightness control keeps working. | ||
| var instanceName = @"DISPLAY\BOE0D79\5&1eca36b7&0&UID4352_0"; |
| // still exposes it. The InstanceName and DevicePath captured in that state must reduce | ||
| // to the same Monitor.Id so WMI can claim the panel and brightness control keeps working. | ||
| var instanceName = @"DISPLAY\BOE0D79\5&1eca36b7&0&UID4352_0"; | ||
| var devicePath = @"\\?\DISPLAY#BOE0D79#5&1eca36b7&0&UID4352#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}"; |
| /// Discover monitors by capability, not by nominal output technology. WMI runs first | ||
| /// over the full QueryDisplayConfig inventory; every display it claims is a | ||
| /// WMI-controllable internal panel. Whatever WMI does not claim is then sent to DDC/CI. | ||
| /// This avoids misrouting a built-in panel that the active (discrete) GPU reports as |
This comment has been minimized.
This comment has been minimized.
…ry comments
Remove OutputTechnology, AdapterId, and TargetId from MonitorDisplayInfo. After the capability-based discovery rework none of them drives any routing/classification decision: OutputTechnology was only echoed in a diagnostic log line, while AdapterId and TargetId were write-only. Also remove the now-dead plumbing in DisplayConfigInventory (GetTargetDeviceInfo no longer returns OutputTechnology) and the unused usings.
Trim redundant/stale comments in the WMI/DDC discovery path (MonitorManager, WmiController, DdcCiController), dropping historical notes ('original three-phase design', 'prior releases') while keeping the design rationale (WMI-first routing for #48587, Monitor.Id stability, crash-scope purpose).
Verified: PowerDisplay + PowerDisplay.Lib build clean (0 warnings); 128/128 Lib unit tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@check-spelling-bot Report🔴 Please reviewSee the 📂 files view, the 📜action log, 👼 SARIF report, or 📝 job summary for details.Unrecognized words (3)eca These words are not needed and should be removedDISPLAYPORT JPN LVDS miracast SVIDEOTo accept these unrecognized words as correct and remove the previously acknowledged and now absent words, you could run the following commands... in a clone of the git@github.com:microsoft/PowerToys.git repository curl -s -S -L 'https://raw.githubusercontent.com/check-spelling/check-spelling/cfb6f7e75bbfc89c71eaa30366d0c166f1bd9c8c/apply.pl' |
perl - 'https://github.com/microsoft/PowerToys/actions/runs/27536878797/attempts/1' &&
git commit -m 'Update check-spelling metadata'OR To have the bot accept them for you, comment in the PR quoting the following line: If the flagged items are 🤯 false positivesIf items relate to a ...
|
Summary of the Pull Request
On dual-GPU laptops, Power Display stopped detecting the built-in panel (and adjusting its brightness) when the discrete GPU drives the display — it showed "can't detect the display". This fixes that by classifying displays by capability (does WMI brightness work on it?) instead of by the nominal
OutputTechnologyvalue, which the discrete GPU misreports for the internal panel.PR Checklist
Detailed Description of the Pull Request / Additional comments
Root cause
On a hybrid / MUX laptop, when the discrete GPU drives the built-in eDP panel,
QueryDisplayConfigreports the panel'sDISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGYasDISPLAYPORT_EXTERNAL(10) instead of theINTERNALflag (0x80000000) it reports under the integrated GPU. It is the same physical panel (same EDID) — only the reported connector type changes with the active GPU.PR #47740 introduced a strict classifier:
OutputTechnology→ internal/external, then internal → WMI-only, external → DDC/CI-only, with no fallback. So under the discrete GPU the built-in panel was classified external and sent to DDC/CI only — but a laptop eDP panel does not speak DDC/CI, so it was dropped and Power Display reported it couldn't detect any monitor. (WmiMonitorBrightnessstill exposes that panel regardless of which GPU drives it, so the panel was actually controllable — it just never got routed to WMI.)Fix: classify by capability, not by nominal output technology
MonitorManagernow runs WMI discovery first over the fullQueryDisplayConfiginventory. Every displayWmiMonitorBrightnessexposes is treated as internal (WMI-controlled); whatever WMI does not claim is routed to DDC/CI. TheOutputTechnology-based classifier is gone.WmiControllermatches the system-wideWmiMonitorBrightnessresults against the full inventory byMonitor.Id. The persistedMonitor.Idis still taken from the matchedDevicePath(byte-identical to the DDC route and to prior releases), so saved brightness/per-monitor settings survive upgrades.MonitorIdentity.FromInstanceNamereduces a WMIInstanceNameto the same canonicalMonitor.IdasFromDevicePath; the separatePnpHardwareKeyhelper is removed.DisplayClassifierandMonitorDisplayInfo.IsInternal(net ~150 fewer lines).Accepted trade-off
A monitor that exposes both
WmiMonitorBrightnessand DDC/CI is now controlled via WMI only and won't get DDC-only features (contrast / volume / input source / color temperature / power). This is uncommon (typical laptop panels are WMI-only; typical external monitors are DDC-only) and is a deliberate decision: it removes the entire class ofOutputTechnologymisclassification bugs while keeping the performance win of not DDC-probing internal panels.Validation Steps Performed
PowerDisplay.csproj) andPowerDisplay.Lib.UnitTests(x64 / Debug) with MSBuild — both succeed, including after merging latestmain(Windows App SDK 2.2.0).FromInstanceNametests — theFromInstanceName == FromDevicePathequivalence invariant and a concrete PowerDisplay unable to detect monitor when using GPU instead of iGPU on laptop #48587 regression case (the BOE panel reported asOutputTechnology=10).OutputTechnology=10 → External → DDC → droppedis now claimed by WMI and controllable.