https://bugs.kde.org/show_bug.cgi?id=518037
Bug ID: 518037
Summary: AutoBrightnessCurve::adjust() produces negative lux
values, corrupting the ambient light brightness curve
Classification: Plasma
Product: kwin
Version First 6.6.2
Reported In:
Platform: Fedora RPMs
OS: Linux
Status: REPORTED
Severity: normal
Priority: NOR
Component: core
Assignee: [email protected]
Reporter: [email protected]
Target Milestone: ---
SUMMARY
AutoBrightnessCurve::adjust() produces negative lux values, corrupting the
ambient light brightness curve
STEPS TO REPRODUCE
1. Connect an ambient light sensor via the net.hadess.SensorProxy D-Bus
interface
2. Enable "Automatically adapt to environment" for all displays
3. Disable one or more monitors (e.g. via a display layout switch)
4. Wait for ambient light to drop to ~2–5 lux
5. Re-enable the previously disabled monitors
6. Inspect autoBrightnessCurve for the re-enabled monitors
OBSERVED RESULT
The curve contains negative lux values for the affected monitors, for example:
[-84.103694, 1.796114, 15.269624, 35.2132, 361.665, 399.63]
[-150.13406, 1.259999, 2.442, 3.442, 34.761232, 63.756]
Because sample() returns 0% brightness when lux <= m_luxAtBrightness[0],
affected monitors drop to minimum brightness in low-light conditions instead of
dimming gradually. Monitors with a healthy curve (e.g. the primary monitor that
was never disabled) behave correctly, causing visible brightness
desynchronization between displays.
EXPECTED RESULT
All lux values in autoBrightnessCurve should be >= 0. The curve should remain
strictly monotonically increasing with non-negative values regardless of
ambient light level, manual brightness adjustments, or monitor on/off state
transitions.
ROOT CAUSE
In AutoBrightnessCurve::adjust(), the computed low control point:
low = (lux - highFactor * high) / (1 - highFactor);
can produce negative values when lux is small (e.g. 2–5 lux) and highFactor is
close to 1. The subsequent downward propagation loop has no lower bound, so
negative
values cascade to all preceding control points via std::min, silently
overwriting
previously correct calibration data.
Proposed fix has three parts:
1. Clamp low to >= 0 after computation:
low = (lux - highFactor * high) / (1 - highFactor);
low = std::max(low, 0.0); // lux cannot be negative
2. Clamp each step of the downward propagation loop:
for (int i = lowMatch - 1; i >= 0; i--) {
m_luxAtBrightness[i] = std::min({...});
m_luxAtBrightness[i] = std::max(m_luxAtBrightness[i], 0.0);
last = m_luxAtBrightness[i];
}
3. Validate the curve when loading from JSON and reset to default if invalid,
so users with already-corrupted configs are recovered automatically on next
start.
SOFTWARE/OS VERSIONS
Linux/KDE Plasma: Fedora 43
KDE Plasma Version: 6.6.2
KDE Frameworks Version: 6.24.0
Qt Version: 6.10.2
ADDITIONAL INFORMATION
This bug was observed specifically when using a custom ambient light sensor
bridge.
The primary monitor (never disabled) retained a healthy curve throughout, while
secondary monitors that were disabled developed negative values after being
re-enabled in a low-light environment.
The corruption is not limited to the first control point - the downward
propagation loop overwrites all preceding points via std::min, so a single
bad adjust() call at index 1 with lux ≈ 2 and highFactor ≈ 0.9 can corrupt
m_luxAtBrightness[0] to values as low as -150, destroying previously learned
calibration data silently.
A secondary symptom was observed the following morning at high ambient light
(~300 lux): the affected monitors reported 100% brightness in the KWin display
controls, yet appeared visibly darker than the primary monitor. I think this
occurs because the corrupted curve had a compressed lux range (e.g.
m_luxAtBrightness[5] = 63 instead of ~600), causing sample() to return 1.0 at
300 lux - but that "100%" maps to a lower actual brightness since the entire
curve is distorted. The UI correctly reflects what the curve says, but the
curve itself is wrong.
--
You are receiving this mail because:
You are watching all bug changes.