Skip to content

[PowerDisplay] Detect built-in panel when driven by the discrete GPU#48637

Open
moooyo wants to merge 3 commits into
mainfrom
yuleng/pd/f/12
Open

[PowerDisplay] Detect built-in panel when driven by the discrete GPU#48637
moooyo wants to merge 3 commits into
mainfrom
yuleng/pd/f/12

Conversation

@moooyo

@moooyo moooyo commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

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 OutputTechnology value, 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, QueryDisplayConfig reports the panel's DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY as DISPLAYPORT_EXTERNAL (10) instead of the INTERNAL flag (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. (WmiMonitorBrightness still 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

  • MonitorManager now runs WMI discovery first over the full QueryDisplayConfig inventory. Every display WmiMonitorBrightness exposes is treated as internal (WMI-controlled); whatever WMI does not claim is routed to DDC/CI. The OutputTechnology-based classifier is gone.
  • WmiController matches the system-wide WmiMonitorBrightness results against the full inventory by Monitor.Id. The persisted Monitor.Id is still taken from the matched DevicePath (byte-identical to the DDC route and to prior releases), so saved brightness/per-monitor settings survive upgrades.
  • New MonitorIdentity.FromInstanceName reduces a WMI InstanceName to the same canonical Monitor.Id as FromDevicePath; the separate PnpHardwareKey helper is removed.
  • Deleted DisplayClassifier and MonitorDisplayInfo.IsInternal (net ~150 fewer lines).

Accepted trade-off

A monitor that exposes both WmiMonitorBrightness and 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 of OutputTechnology misclassification bugs while keeping the performance win of not DDC-probing internal panels.

Validation Steps Performed

  • Built the Power Display app (PowerDisplay.csproj) and PowerDisplay.Lib.UnitTests (x64 / Debug) with MSBuild — both succeed, including after merging latest main (Windows App SDK 2.2.0).
  • Ran the unit test suite: 128/128 pass, including new FromInstanceName tests — the FromInstanceName == FromDevicePath equivalence invariant and a concrete PowerDisplay unable to detect monitor when using GPU instead of iGPU on laptop #48587 regression case (the BOE panel reported as OutputTechnology=10).
  • Traced the fix against the reporter's diagnostic logs: the panel that previously went OutputTechnology=10 → External → DDC → dropped is now claimed by WMI and controllable.
  • Reviewed the diff for regressions (Monitor.Id persistence, monitor blacklist, mirror mode, dual-internal-panel devices, external-only desktops).

Yu Leng and others added 2 commits June 15, 2026 16:57
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
@github-actions

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>
@github-actions

Copy link
Copy Markdown

@check-spelling-bot Report

🔴 Please review

See the 📂 files view, the 📜action log, 👼 SARIF report, or 📝 job summary for details.

Unrecognized words (3)

eca
Miracast
misrouting

These words are not needed and should be removed DISPLAYPORT JPN LVDS miracast SVIDEO

To 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
on the yuleng/pd/f/12 branch (ℹ️ how do I use this?):

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:
@check-spelling-bot apply updates.

If the flagged items are 🤯 false positives

If items relate to a ...

  • binary file (or some other file you wouldn't want to check at all).

    Please add a file path to the excludes.txt file matching the containing file.

    File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.

    ^ refers to the file's path from the root of the repository, so ^README\.md$ would exclude README.md (on whichever branch you're using).

  • well-formed pattern.

    If you can write a pattern that would match it,
    try adding it to the patterns.txt file.

    Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.

    Note that patterns can't match multiline strings.

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.

PowerDisplay unable to detect monitor when using GPU instead of iGPU on laptop

2 participants