说明
哪一层在把你的屏幕调暗:硬件、软件,还是都不是
两个 App 都可以显示「亮度 40%」,画面却可以完全不同。 原因是亮度由不同的层承载,而其中只有一层碰得到背光。
四种状态
一个能用的实现必须把这四种状态显式建模,因为整件事的关键就是 「从硬件往下跳到软件」。它们不能互相替换:
- 硬件——面板自己的背光通过 DDC/CI 应答。这是真正的亮度: 像素背后的光变少了,黑还是黑。
- 软件——改写伽马表。画面变暗,背光没变。 在 contrast 为 1 时它是纯缩放,黑仍然是黑;一旦对比度低于 1 就不是了—— 对比度那一项绕 0.5 旋转,把斜坡底部推到零以上, 而那个才是让黑变成深灰的原因,不是调光本身。
- 不可用——什么都不行。诚实的做法是直接说出来, 而不是假装一个滑块在起作用。
- 未知——还没探测过。它和「不可用」是两回事,这是有意的: 一个是「我们问了,面板说不」,另一个是「我们还没问」。
为什么「未知」不能等于「不可用」
把这两者合并,就是 App 在一块**它从未试过**的显示器上, 提前告诉你「不支持」。分开它们只需要源码里的一个词,却能避免一次错误诊断。
那些延时是设计的一部分
回退不是「重试一次」。面板在唤醒之后需要一段时间才能重新应答 DDC/CI—— 在通知刚落地的那一刻重放,正是朴素唤醒处理会失败的原因。 一个真正的实现在唤醒后等 2.5 秒,然后按 1、2、4 秒退避重试。
为什么这道阶梯要保持可测试
重试阶梯不依赖窗口工具包,也不依赖任何具体的 DDC 类型: 调用方把写入器和 sleeper 注入进来。 这正是它能在「面板完全不支持 DDC/CI」的机器上被跑到的原因—— 而那恰恰是唯一一类否则永远走不到这段代码的机器。
诚实的边界
- 软件调光不是「一样但更便宜」。它改的是画面,而且在低值时会明显地把黑位抬起来。
- 这些具体延时是某一个实现对着自己的硬件量出来的。它们不是规范,面板各不相同。
- 硬件控制也不是永远更好:在一块应答很慢的面板上,混合方案可能比干净的软件调光更糟。