https://bugs.kde.org/show_bug.cgi?id=523341

            Bug ID: 523341
           Summary: Backlight helper applies brightness on the wrong
                    device scale when spawned while the panel connector is
                    disabled (hybrid GPU, two backlight devices)
    Classification: Plasma
           Product: plasmashell
      Version First 6.6.5
       Reported In:
          Platform: Ubuntu
                OS: Linux
            Status: REPORTED
          Severity: normal
          Priority: NOR
         Component: Power management & brightness
          Assignee: [email protected]
          Reporter: [email protected]
  Target Milestone: 1.0

DESCRIPTION

On a hybrid-GPU laptop (Intel Arrow Lake iGPU driving the internal panel via
i915, NVIDIA RTX 5070 Ti Mobile with driver 595.71.05 open) the kernel exposes
two backlight devices for the same internal panel:

- intel_backlight, type raw, max_brightness 496 (the real one; parent is the
  i915 eDP connector)
- nvidia_0, type raw, max_brightness 100 (registered by the NVIDIA driver even
  though the panel is muxed to the iGPU; its parent is the dGPU PCI device)

Every time the screen turns off on idle timeout and is woken by user input, the
panel comes back roughly 5x brighter than its set value, while the brightness
slider/OSD still shows the old (correct) value. Clicking the slider re-applies
the correct brightness.

I traced writes to /sys/class/backlight/*/brightness with a bpftrace kprobe on
kernfs_fop_write_iter during a live occurrence. The writer is powerdevil's
KAuth helper (backlighthelper), writing BOTH devices in lockstep.

ROOT CAUSE (daemon/controllers/backlighthelper_linux.cpp, Plasma/6.6 branch,
still present on current master including commit 90bebf783d "controllers:
remove brightness animations"):

1. The helper is DBus-activated per request, and each fresh helper process
   re-enumerates /sys/class/backlight in its constructor.

2. The undim restore on wake-from-idle reaches the helper while the eDP DRM
   connector is still disabled. In getBacklightTypeDevices(), the check of
   <device>/device/enabled therefore leaves rawEnabled empty, and the code
   falls through to the rawAll list.

3. rawAll is sorted with QDir::Name | QDir::Reversed (the comment says this is
   to prioritize acpi_video1 over acpi_video0). Reverse-alphabetical order
   puts nvidia_0 before intel_backlight, so m_devices.constFirst() is now
   nvidia_0 with max 100. Note the client side of powerdevil detected the
   devices earlier (while the connector was enabled), so it holds
   intel_backlight (max 496) as the reference scale and sends raw values on
   that scale.

4. writeBrightness() rescales the incoming value from the FIRST device's max
   onto every device: new = value * device_max / first_max. With first_max
   now 100 instead of 496, the panel's correct raw target (e.g. 21, which is
   4% of 496) is reinterpreted as "21 percent": intel_backlight is written
   21 * 496 / 100 = 104 (about 5x too bright) and nvidia_0 is written 21.

5. The client-side BacklightBrightness sees the sysfs change, classifies it as
   "External brightness change observed", and keeps its own tracked value.
   The slider therefore does not move, and clicking it re-applies the correct
   brightness through a helper instance that (with the panel now enabled)
   enumerates intel_backlight first again.

Two independently captured occurrences match this arithmetic exactly:
set 3% (raw 16) woke to 79/496 + 16/100; set 4% (raw 21) woke to 104/496 +
21/100 (both = the raw value as a percentage).

EVIDENCE

bpftrace (kprobe:kernfs_fop_write_iter, filtered to files named "brightness")
during the wake restore; note the same short-lived helper pid writing both
devices alternately:

  23:32:50 backlighthelper(pid 18610) wrote intel_backlight/brightness  
  23:32:50 backlighthelper(pid 18610) wrote nvidia_0/brightness  
  23:32:50 backlighthelper(pid 18610) wrote intel_backlight/brightness  
  23:32:50 backlighthelper(pid 18610) wrote nvidia_0/brightness  
  [...repeats through the animation ramp...]  

Sysfs state sampled every 2s (intel=brightness/actual_brightness on 0..496,
nvidia on 0..100, dbus = powerdevil's tracked value on 0..10000):

  23:31:35 dimmed        intel=7/7     nvidia=16  dbus_internal=400  
  23:32:35 screens off   intel=7/0     nvidia=16  dbus_internal=400  
  23:32:50 woke by mouse intel=104/104 nvidia=21  dbus_internal=400   <- bug  
  23:33:29 slider click  intel=21/21   nvidia=21  dbus_internal=400   <- fixed  

journalctl --user -u plasma-powerdevil with org.kde.powerdevil.debug=true at
an earlier occurrence of the same bug (set 3%, raw 16):

  org.kde.powerdevil: DimDisplay: restoring brightness on wake-up from idle  
  org.kde.powerdevil: Set screen brightness dimming ratio with ID "DimDisplay"
to 1  
  org.kde.powerdevil: [BacklightBrightness]: Udev device changed brightness to:
29 for ".../card2-eDP-1/intel_backlight"  
  org.kde.powerdevil: [BacklightBrightness]: External brightness change
observed: 29 / 496  
  [...ramp continues: 34, 39, 44, ... 79 = 16% of 496...]  

STEPS TO REPRODUCE

1. Hybrid-GPU laptop where the internal panel is driven by the iGPU and the
   NVIDIA driver additionally registers nvidia_0 (or any second raw backlight
   device with a different max_brightness).
2. Set panel brightness to a low value, e.g. 3%.
3. Let the machine idle until the screen dims and then turns off
   (for fast repro set [AC][Display] DimDisplayIdleTimeoutSec=60 and
   TurnOffDisplayIdleTimeoutSec=120 in powerdevilrc).
4. Wake with mouse/keyboard.

OBSERVED RESULT

Panel lights up at (raw_value) percent instead of the set brightness, about 5x
too bright in my case. Slider still shows the set value.

EXPECTED RESULT

Panel restores the set brightness.

SOFTWARE/OS VERSIONS

Operating System: Ubuntu 26.04 LTS  
KDE Plasma Version: 6.6.5  
KDE Frameworks Version: 6.24.0  
Qt Version: 6.10.2  
Kernel Version: 7.0.0-28-generic (64-bit)  
Graphics Platform: Wayland  
GPUs: Intel Arrow Lake-S [8086:7d67] (i915) + NVIDIA GB205M RTX 5070 Ti Mobile
[10de:2f58] (nvidia 595.71.05 open kernel module)

ADDITIONAL INFORMATION

- The bug requires the helper to spawn while the panel connector is disabled;
  that is exactly the state during the wake/undim restore, so it hits on
  every single idle wake on affected hardware.
- Any brightness write in that window (not just undim) takes the same path.
- Relationship to existing reports (checked before filing, not duplicates):
  - Bug 399646 (multi-GPU wrong backlight device, CONFIRMED): umbrella bug
    about device selection. This report is a specific, line-level defect in
    the "write to all raw devices with rescaling" approach added for that
    bug around 5.25: the reference scale is re-derived per helper spawn and
    flips when the panel connector is disabled. Keys/slider work fine here;
    the corruption happens only on writes issued while the connector is off.
  - Bug 510294 (panel brighter than the slider indicates after sleep/lock,
    touching the slider fixes it): identical user-visible symptom, no root
    cause identified there. Possibly the same underlying defect if those
    machines also expose multiple raw backlight devices with different
    max_brightness; the analysis here may explain it.
  - Bug 461479 (backlight briefly flashes to full on wake with dim + screen
    off configured, RESOLVED in ~6.4): same trigger combination but a
    transient flash; this bug produces a persistent wrong level equal to
    raw_value percent, still present in 6.6.5.
  - Bug 522171 (DDC value not reapplied to external monitor after wake) and
    bug 513809 (stale dimming multiplier on secondary monitors after sleep):
    different mechanisms (DDC restore / dim state), not the raw-scale
    mix-up described here.
- Suggested fixes: pin the device order/reference scale in the client (pass
  the expected device or its max along with the value), or have the helper
  remember/receive the reference device instead of re-deriving it per spawn,
  or drop the "enabled" filter dependence for scale selection.
- Local workaround that fully fixes it: shadow nvidia_0's sysfs directory
  with an empty read-only tmpfs mount so only one backlight device is
  visible.

-- 
You are receiving this mail because:
You are watching all bug changes.

Reply via email to