背光
屏幕亮度調節可能有點難以控制。在一些計算機上,可能缺失了物理硬件開關,並且軟件解決方案也可能工作得不好。但是通常地,我們可以對於給定的硬件,找到對應的方法來調節屏幕亮度。本文旨在總結所有可能的調節屏幕亮度和背光(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