背光
屏幕亮度调节可能有点难以控制。在一些电脑上,可能缺失了物理硬件开关,并且软件解决方案也可能工作得不好。但是通常地,我们可以对于给定的硬件,找到对应的方法来调节屏幕亮度。本文旨在总结所有可能的调节屏幕亮度和背光(Backlight)的方法。
我们有很多方法可以用来控制显示器、笔记本电脑或者集成面板(比如 iMac)。根据这些(英文)讨论(英文)和这个维基页面(英文),控制的方法可以分为以下几种:
- 亮度由供应商指定的热键控制,而操作系统没有对应的接口用于调节屏幕亮度。
- 亮度由 ACPI,图形或者平台的驱动来控制。在这种情况下,亮度控制通过
/sys/class/backlight
暴露给用户。用户空间基于此,提供了背光实用程序。 - 可以通过 setpci 来写入到显卡的寄存器,来控制亮度。
硬件接口[编辑 | 编辑源代码]
ACPI[编辑 | 编辑源代码]
屏幕背光的亮度由背光LED或阴极的电平来调节,且通常由视频ACPI内核模块调节。此模块的接口以位于/sys/class/backlight/
的sysfs(5)目录的形式提供。
具体的目录名称由显卡型号决定。
$ ls /sys/class/backlight/
acpi_video0
此处,背光由ATI显卡管理。Intel显卡对应的目录名为intel_backlight
。下方的例子使用acpi_video0
。如果使用Intel显卡,直接将例子中的acpi_video0
替换为intel_backlight
即可。
目录包含以下文件与子目录:
$ ls /sys/class/backlight/acpi_video0/
actual_brightness brightness max_brightness subsystem/ uevent bl_power device/ power/ type
最大亮度可从max_brightness
处读取,通常为15。
$ cat /sys/class/backlight/acpi_video0/max_brightness
15
要设置亮度,可以向brightness
写入代表亮度等级的数值。数值大于最大亮度值可能会导致错误。
# echo 5 > /sys/class/backlight/acpi_video0/brightness
默认情况下,仅root
可以通过此方法更改亮度。要让video
组的用户也可以更改亮度,可以使用以下udev规则:
/etc/udev/rules.d/backlight.rules
ACTION=="add", SUBSYSTEM=="backlight", RUN+="/bin/chgrp video $sys$devpath/brightness", RUN+="/bin/chmod g+w $sys$devpath/brightness"
内核命令行选项[编辑 | 编辑源代码]
有时由于主板实现不同,或者ACPI本身的异常,ACPI可能无法正常工作。这会导致一些奇怪的情况,比如亮度通知不准确。受影响的设备包括双显卡笔记本(比如NVIDIA/Radeon独显+Intel/AMD集显)。此外,ACPI有时需要注册自己的acpi_video0
背光源,即使已经存在一个背光源(如intel_backlight
),这可以通过添加以下内核参数之一来完成:
acpi_backlight=video acpi_backlight=vendor acpi_backlight=native
如果更改acpi_video0
背光源无法真正更改亮度,可能需要使用acpi_backlight=none
。
- 在使用NVIDIA Optimus的笔记本上,内核参数
nomodeset
可能与背光调节冲突。 - 在华硕(ASUS)笔记本上可能需要加载
asus-nb-wmi
内核模块。 - 在Dell XPS 13上禁用Legacy boot会导致背光支持异常。
Udev规则[编辑 | 编辑源代码]
ACPI接口可用时,背光等级可以在引导时使用udev规则设置:
/etc/udev/rules.d/81-backlight.rules
# Set backlight level to 8 SUBSYSTEM=="backlight", ACTION=="add", KERNEL=="acpi_video0", ATTR{brightness}="8"
setpci[编辑 | 编辑源代码]
部分情况下(比如Intel Mobile 945GME [1]),可以通过设置显卡寄存器来调整背光。请注意,这种方法是通过直接操作硬件来调整背光,可能有风险,而且通常不是一个好主意。并非所有的显卡都支持这种方法。
使用此方法时,需要先使用lspci
来确定显卡的位置。
# setpci -s 00:02.0 F4.B=0
外部显示器[编辑 | 编辑源代码]
DDC/CI(显示数据通道命令接口)可用于通过I2C与实现MCCS(显示器控制命令集)的外部显示器通信。DDC可以在受支持的显示器上控制亮度、对比度、输入等。可以通过OSD(屏幕菜单,On-Screen Display)面板操作的设置通常也可以通过DDC管理。如果/dev/i2c-*
设备不存在,可能需要加载i2c-dev
内核模块。
ddcutil包可以用于查询和设置亮度相关设置:
# ddcutil capabilities | grep "Feature: 10"
Feature: 10 (Brightness)
# ddcutil getvcp 10
VCP code 0x10 (Brightness ): current value = 60, max value = 100
# ddcutil setvcp 10 70
或者也可以使用ddcci-driver-linux-dkmsAUR以在sysfs中暴露外部显示器接口。加载ddcci
内核模块后,可以使用任意的背光实用程序。
- 同时使用
ddcci
和i2c-dev
可能导致资源冲突,类似于Device or resource busy
(设备或资源忙)的报错。 - 使用NVIDIA专有驱动的用户可能需要向
/etc/X11/xorg.conf.d/20-nvidia.conf
(由nvidia-xconfig生成)的Device
部分添加Option "RegistryDwords" "RMUseSwI2c=0x01; RMI2cSpeed=100"
,或向/etc/modprobe/conf.d/nvidia.conf
添加options nvidia NVreg_RegistryDwords=RMUseSwI2c=0x01;RMI2cSpeed=100
。使用grep RegistryDwords /proc/driver/nvidia/params
命令,并检查其中的值是否为空来验证设置是否被正确应用。参见[2]和[3]。 - 若显示器启用了会自动调整VCP功能的功能(比如动态对比度或BenQ显示器的视力保护(Eye Care)技术),
ddcutil
可能会无法设置这些VCP功能。 - 要将屏幕亮度控制绑定到快捷键,为非超级用户启用访问相关的I2C设备的权限可能会方便一些。通过添加
i2c
用户组并调整udev让I2C设备的拥有者为该用户组即可。参见[4]。 - 若安装了ddcutil包,该包提供
/usr/share/ddcutil/data/90-nvidia-i2c.conf
文件,可以直接复制到/etc/X11/xorg.conf.d/
,不用手动编写Xorg配置文件。该包同时为udev规则提供/usr/share/ddcutil/data/45-ddcutil-i2c.rules
和/usr/share/ddcutil/data/45-ddcutil-usb.rules
。
关闭背光[编辑 | 编辑源代码]
关闭背光(Backlight)(比如说当锁屏的时候),可以有效地保护电源电量。理想情况下,在Xorg图形会话中,下列命令应该可以运行:
$ xset dpms force off
这个背光(Backlight)可以通过鼠标的移动或者键盘的输入来再次打开。或者,xset s
应该可以用来完成相似的作用。
如果上面的命令没有完成,那么可能是因为 vbetool 起作用。注意,然而,在这种情况下,背光(Backlight)必须手动再次打开,(关闭背光的)命令如下:
$ vbetool dpms off
开启背光的的命令是:
$ vbetool dpms on
比如,这个命令可以用于在使用 acpid 的时候,在关闭笔记本盖子的时候使用(来关上显示器背光)。
保存与恢复能力[编辑 | 编辑源代码]
systemd包提供了模板服务systemd-backlight@.service
,默认启用且为“静态”单元。该服务在关机时保存背光亮度等级,并在开机时恢复。此模板服务使用#ACPI段落提到的ACPI方法,且会为/sys/class/backlight/
下的每一个文件夹生成一个对应的服务。比如,如果有文件夹名为acpi_video0
,则会生成一个叫systemd-backlight@backlight:acpi_video0.service
的服务。如果希望开机时设置背光使用其他方法,推荐停止systemd-backlight服务恢复背光,只需要设置内核参数systemd.restore_state=0
。参见systemd-backlight@.service(8)。
acpi_video1
则禁用systemd-backlight@backlight:acpi_video1
)。此外,brilloAUR和light包等实用程序也有保存与恢复背光的能力。提及到的这两个可以为每个用户单独恢复屏幕亮度(尚无systemd单元支持这么做)。
背光实用程序[编辑 | 编辑源代码]
video
(或input
)用户组的成员更改亮度。包名 | 控制键盘背光 | 适应环境光 | 语言 | 许可协议 | 注释 |
---|---|---|---|---|---|
acpilight包 | 是 | 否 | Python3 | GPL-3.0-or-later | 提供"xbacklight"可执行程序 |
backlight_controlAUR | 否 | 否 | C | MIT | 非常小巧和简单。支持相对调整。 |
blightAUR | 是 | 否 | Python3 | ISC | 使用logind接口。仅限于本地用户,但不要求为suid或video用户组成员。 |
brightdAUR | 否 | 否 | C | GPL-2.0 | 当有一段时间没有用户输入时,会调暗屏幕。 |
brightnessctl包 | 是 | 否 | C | MIT | - |
brilloAUR | 是 | 否 | C | GPL-3.0-only | 支持平滑和相对调整。 |
clightAUR | 是 | 是 | C | GPL-3.0-or-later | 管理屏幕色温(仅Xorg),且在一段时间后平滑调暗亮度。支持环境光传感器[5]。支持将摄像头用作环境光传感器。 |
enlighten-gitAUR | 是 | 否 | C | GPL-3.0-or-later | - |
illum-gitAUR | 否 | 否 | C | AGPL-3.0 | 会对按键做出反应。 |
light包 | 是 | 否 | C | GPL-3.0-only | 无额外依赖。不依赖X服务器。 |
luxAUR | 否 | 否 | Shell | MIT | - |
macbook-lighterAUR | 是 | 是 | Bash,Perl | GPL | 用于Macbook的屏幕/键盘背光CLI程序,自动适应环境光。 |
wlr-brightness-gitAUR | 否 | 否 | C | MIT | 还支持需要伽马调整的新一些的OLED显示器。使用wlroots。 |
wlumaAUR | 是 | 是 | Rust | ISC | 根据屏幕内容和环境光自动调节亮度。可以使用摄像头或时间模拟环境光传感器。支持键盘和外部显示器。使用wlroots。 |
ybacklightAUR | 否 | 否 | Perl | GPL-2.0 | 与xbacklight类似但使用sysfs驱动程序的小型Perl脚本。 |
xbacklight-notifyAUR | 否 | 否 | C | MIT | 简单的通知守护进程 |
XF86MonBrightnessUp
和XF86MonBrightnessDown
键盘按键。xbacklight[编辑 | 编辑源代码]
可以使用xorg-xbacklight包设置亮度。
要设置亮度为最大值的50%:
$ xbacklight -set 50
可以使用增量代替绝对值,例如增加或减少10%的亮度:
$ xbacklight -inc 10 $ xbacklight -dec 10
如果报错“No outputs have backlight property”(没有输出拥有背光属性),是因为xrandr/xbacklight没有选择/sys/class/backlight
中正确的目录。可以通过在/etc/X11/xorg.conf.d/20-video.conf
中设置Device(设备)部分的Backlight
选项来指定目录。比如,目录名为intel_backlight
且使用Intel驱动,则该部分可按下述配置:
/etc/X11/xorg.conf.d/20-intel.conf
Section "Device" Identifier "Intel Graphics" Driver "intel" Option "Backlight" "intel_backlight" EndSection
参见FS#27677和 https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=651741 。
如果启用Intel Fastboot,也有可能会报错No outputs have backlight property
。这种情况下,使用以上方法可能导致Xorg在启动时崩溃。此时建议禁用Intel Fastboot以解决问题。已知这会导致亮度控制的问题。
light[编辑 | 编辑源代码]
安装light包并将你使用的用户添加到video
用户组。
将背光亮度提高5%:
$ light -A 5
将背光亮度降低5%:
$ light -U 5
将背光亮度设为100%:
$ light -S 100
在GNOME中使用DBus[编辑 | 编辑源代码]
亮度也可以像GNOME设置那样进行调整。使用此方法时,GNOME的用户界面会反映出所做的更改。
$ gdbus call --session --dest org.gnome.SettingsDaemon.Power --object-path /org/gnome/SettingsDaemon/Power --method org.freedesktop.DBus.Properties.Set org.gnome.SettingsDaemon.Power.Screen Brightness "<int32 50>"
使用该方法也可以实现用键盘控制亮度。
$ gdbus call --session --dest org.gnome.SettingsDaemon.Power --object-path /org/gnome/SettingsDaemon/Power --method org.gnome.SettingsDaemon.Power.Screen.StepUp $ gdbus call --session --dest org.gnome.SettingsDaemon.Power --object-path /org/gnome/SettingsDaemon/Power --method org.gnome.SettingsDaemon.Power.Screen.StepDown
在KDE中使用DBus[编辑 | 编辑源代码]
参见 https://userbase.kde.org/KDE_Connect/Tutorials/Useful_commands#Brightness_settings 。
色彩校正[编辑 | 编辑源代码]
色彩校正并不会改变实际背光的功率,仅仅只是修改视频查找表。也就是说,这样并不会像上述方法一样,调低亮度就可以节省电量。无论如何,如果背光控制完全不可用的时候(比如使用OLED屏幕的台式机和笔记本),可以尝试用色彩校正。
- Clight — 旨在全面管理显示器的用户守护程序实用程序。它可以根据一天中的当前时间来管理屏幕温度,就和Redshift一样。如果配置文件中未设置纬度或经度,它将尝试使用geoclue包来检索用户位置。它也支持日出和日落的固定时间。
- icc-brightness — 通过应用ICC颜色配置文件控制OLED显示器亮度。
- Monica — 显示器校准工具。它作为xgamma的前端来改变伽玛校正。
- https://web.archive.org/web/20090815224839/http://www.pcbypaul.com/software/monica.html || monicaAUR
- xcalib — 轻量级监视器校准加载程序,可以加载跨桌面应用程序共享的ICC监视器配置文件。
- xgamma — 更改监视器的伽马校正。
Wayland[编辑 | 编辑源代码]
Redshift暂不支持Wayland(除非打补丁或者使用衍生版本,比如redshift-wayland-gitAUR)。但是仍可以在启动混成器前在tty中应用想要的色温设置。比如:
$ redshift -m drm -PO 3000
或者,部分混成器也支持运行时应用色彩校准:
- GNOME可以使用内置的夜间模式。
- KDE Plasma也可以使用内置的夜间模式。
- Sway 1.0或其他基于wlroots的混成器,包括Orbital,可以使用Redshift的衍生版本、gammastep包、clightAUR、wlsunset-gitAUR、wl-gammarelayAUR。
Xorg:使用xrandr调节视觉亮度[编辑 | 编辑源代码]
xrandr可以用于调节视觉亮度。
要将视觉亮度调至最大值以上(其问题与上方提到的NVIDIA设置的情况相同):
$ xrandr --output output_name --brightness 2
这会将画面亮度翻倍(大致上),但是这么调高亮度会牺牲色彩的质量,但它特别适合环境光非常明亮的情况下(如阳光直射)。
也可以指定小于1(例如 0.5)的值来降低视觉亮度,这在显示设备位于暗处且没有背光控制可用时(例如台式机)是有用的。
例子中的所连接设备的output name(输出名称)可以通过调用xrandr
确定:
$ xrandr | grep -w connected | cut -f '1' -d ' '
也可以修改以上命令并设置为命令别名来快速更改亮度:
$ alias b='echo -e "enter brightness:\n"; read val; xrandr --output output name --brightness "${val}"'
要在背光文件修改时自动调用xrandr,可以像这样使用oled-shmoledAUR:
$ oled_shmoled output_name
NVIDIA设置[编辑 | 编辑源代码]
NVIDIA专有驱动的用户可以通过nvidia-settings实用程序的“X Server Color Correction”部分修改显示亮度。但请注意,此处的“亮度”与背光的亮度(光的强度)没有任何关系,仅仅只是调整色彩输出。仅当其他手段全部无法使用时可以使用该方案,但要注意这并不能帮助节约电量。增加此“亮度”会完全扭曲色彩输出,使得最终显示效果类似于过曝。
疑难解答[编辑 | 编辑源代码]
背光PWM调制频率(仅Intel i915)[编辑 | 编辑源代码]
带LED背光的笔记本电脑有时会出现屏幕闪烁。这是因为控制LED背光亮度的最有效方法是快速开关LED,改变它们开启的时间长度。
然而,LED开关的频率,即所谓的PWM(脉宽调制)频率,可能不够高,以至于眼睛无法将其感知为恒定的亮度,而是看到闪烁的情况。这会导致一些人出现头痛和眼睛疲劳等症状。
如果使用Intel i915 GPU,则可以调整PWM频率以消除闪烁现象。
PWM的周期(与频率互为倒数)储存于0xC8254
寄存器的两个高位字节(如果使用Intel GM45芯片组,则寄存器地址为0x61254
)。要操作寄存器的值,请从官方源安装intel-gpu-tools包。
要增加频率,就需要减少周期。比如:
# intel_reg read 0xC8254
0xC8254 : 0x12281228
要将PWM频率加倍,请将两个高位字节(4个高位十六进制数位)除以2,然后向寄存器的两个高位字节写入结果,保持低位字节不变:
# intel_reg write 0xC8254 0x09141228
您可以使用在线计算器来计算所需的值 https://devbraindom.blogspot.com/2013/03/eliminate-led-screen-flicker-with-intel.html
要自动设置新频率,请考虑编写udev规则或安装intelpwm-udevAUR。
亮度反转(仅Intel i915)[编辑 | 编辑源代码]
症状:
- 安装xf86-video-intel包后,systemd-backlight.service在系统引导时将背光关闭
- 可能的解决方案:屏蔽(mask)systemd-backlight.service
- 从X切换到另一个虚拟终端(VT)会关闭背光
- 亮度调节键/按钮效果相反(即按亮度+反而会让屏幕变暗)
可通过添加i915.invert_brightness=1
至内核参数列表来解决这个问题。
无法控制eDP面板亮度(仅Intel i915)[编辑 | 编辑源代码]
嵌入式显示端口(eDP)v1.2 为通过AUX通道工作的背光和其他控件引入了新的显示面板控制协议 [7]
默认情况下,i915驱动可能尝试使用PWM调节背光亮度,此时可能无法工作。
要通过使用AUX通道写入DPCD寄存器来设置背光,请设置i915.enable_dpcd_backlight=1
内核参数。
sysfs修改了,但亮度无变化[编辑 | 编辑源代码]
在某些系统中,键盘上的亮度热键可以正确地修改/sys/class/backlight/acpi_video0/actual_brightness
中ACPI接口的值,但是屏幕的亮度却不会改变。桌面环境提供的亮度调节可能也没有作用。
如果您已经测试了推荐的内核参数,并且只有xbacklight
工作,那么您可能面临者BIOS和内核驱动程序之间的不兼容。
在这种情况下,唯一的解决方案是等待来自BIOS或GPU驱动程序制造商的修复。
临时的修复方案为使用inotify内核API来在每次/sys/class/backlight/acpi_video0/actual_brightness
的值更改的时候调用xbacklight
。
首先安装inotify-tools包。然后创建含有调用inotify的脚本,让其在引导时启动,或者也可以通过自动启动手段启动。
/usr/local/bin/xbacklightmon
#!/bin/sh path=/sys/class/backlight/acpi_video0 luminance() { read -r level < "$path"/actual_brightness factor=$((100 / max)) printf '%d\n' "$((level * factor))" } read -r max < "$path"/max_brightness xbacklight -set "$(luminance)" inotifywait -me modify --format '' "$path"/actual_brightness | while read; do xbacklight -set "$(luminance)" done
MATE下背光不工作[编辑 | 编辑源代码]
Xfce下背光按键不工作[编辑 | 编辑源代码]
在xfce4中,Xfce4电源管理器处理亮度按键。
在部分Xfce环境中,“处理显示亮度按键”(Handle display brightness keys)的设置可能默认为关闭。
要再次启用亮度按键,打开Xfce4电源管理器对话框并开启“处理显示亮度按键”:
$ xfce4-power-manager -c
xbacklight返回:No outputs have backlight property[编辑 | 编辑源代码]
取决于安装的显卡,有时来自xorg-xbacklight包的xbacklight可能会返回消息“No outputs have backlight property”(没有输出拥有背光属性)。安装acpilight包,此包提供备选的xbacklight程序,可能可以工作。
使用amdgpu驱动时每次重启后亮度都会变为最大值[编辑 | 编辑源代码]
由于近期amdgpu驱动的bug,背光的actual_brightness
值可能返回十六位整型数值,而max_brightness
中指定的数值为八位。这会导致systemd-backlight
服务在系统引导时尝试恢复亮度,但尝试恢复到的亮度值总是大于最大亮度值,进而变成调为最大亮度(255)。
在该错误没有得到解决的期间,一种可能的解决方法是在恢复之前将存储的亮度修改(截断)到正确的范围内。这可以通过脚本和服务单元来完成:
fix-brightness.sh
#!/bin/bash # Change the line below according to your hardware BRIGHTNESS_FILE="/var/lib/systemd/backlight/pci-0000:04:00.0:backlight:amdgpu_bl0" BRIGHTNESS=$(cat "$BRIGHTNESS_FILE") BRIGHTNESS=$(($BRIGHTNESS*255/65535)) BRIGHTNESS=${BRIGHTNESS/.*} # truncating to int, just in case echo $BRIGHTNESS > "$BRIGHTNESS_FILE"
fix-brightness.service
[Unit] Description=Convert 16-bit brightness values to 8-bit before systemd-backlight applies it Before=systemd-backlight@backlight:amdgpu_bl0.service [Service] Type=oneshot ExecStart=<path to the script above> [Install] WantedBy=multi-user.target
在部分系统上,驱动返回的背光等级确实在正确的范围[0, 255]内,但systemd仍然不能恢复为正确的亮度值。这有可能是由于内核中的冲突。这种情况下,截断亮度等级没有用处,因为已经在正确范围内。临时的解决方法包括在关机前向systemd保存亮度等级。这可以通过以下脚本和服务单元来完成:
fix-brightness.sh
#!/bin/sh # Backlight level from systemd's perspective (change if needed) readonly SYSTEMD_BACKLIGHT_FILE='/var/lib/systemd/backlight/pci-0000:04:00.0:backlight:amdgpu_bl0' # Backlight level from AMDGPU driver readonly AMDGPU_BACKLIGHT_FILE='/sys/class/backlight/amdgpu_bl0/brightness' # Read current value from the driver and apply it to systemd readonly AMDGPU_BACKLIGHT_VALUE=$(cat "$AMDGPU_BACKLIGHT_FILE") echo "$AMDGPU_BACKLIGHT_VALUE" > "$SYSTEMD_BACKLIGHT_FILE"
fix-brightness.service
[Unit] Description=Save brightness value from AMDGPU DefaultDependencies=no After=final.target [Service] Type=oneshot ExecStart=<到上方脚本的路径> [Install] WantedBy=final.target