內核級顯示模式設置
內核級顯示模式設置 (KMS) ,作用是可以在內核級別而不是最終用戶級別切換顯示解析度和顏色深度。
Linux 內核的 KMS 實現支持在 framebuffer 中使用原生解析度和即時終端(tty)切換。KMS 使用了更新的技術(例如 DRI2),可以減少失真、增強3D性能,甚至使用內核空間節能功能。
背景
以前,設定顯卡是 X 伺服器的工作。所以虛擬終端不可能提供漂亮的圖像效果。同時,每次使用Ctrl+Alt+F1~7從X切換到虛擬終端時,x伺服器必須將顯卡的控制權交給內核,這個流程顯得低效並且會導致閃爍。將控制權切回到X伺服器同樣是一個「痛苦」的過程。
使用內核模式設置後,內核可以設定顯卡的模式。這樣開機啟動即可看到漂亮的顯示畫面,在 X 圖形界面 和 終端 之間也可以快速切換,還有其他的一些優點。
配置
不管使用什麼方法,都需要先「禁用」下列項:
- 所有引導加載程序中的
vga=選項,這個選項與 KMS 的原生解析度設置衝突。 - 所有
video=選項,這個選項會啟動幀緩衝,導致驅動衝突。
KMS 晚啟動
Intel, Nouveau, ATI 和 AMDGPU 驅動已經為所有晶片組提供了 KMS 支持。這些驅動也會自動啟用 KMS,無須額外操作。
閉源的 NVIDIA 驅動從 364.12 開始支持 KMS,並且從 560.35.03-5 版本開始默認啟用。舊版本需要手動啟用。
KMS 早啟動
KMS通常是在initramfs 階段之後開始初始化,但是你也可以在initramfs的階段啟用KMS。將所需的視頻驅動模塊加入 initramfs 配置文件:
-
AMDGPU 驅動加入
amdgpu; 老的 ATI 驅動加入radeon -
Intel 卡加入
i915 - 開源的 Nouveau 驅動加入
nouveau - 對於樹外 NVIDIA 驅動,加入
nvidia nvidia_modeset nvidia_uvm nvidia_drm。見 NVIDIA#DRM 內核級顯示模式設置 以獲取詳細信息。 - Matrox 顯卡加入
mgag200。 -
QEMU 顯卡使用(qemu 選項
-vga type或 libvirt<video><model type='type'>[2]):-
bochs對應std(qemu) 和vga/bochs(libvirt), -
virtio-gpu對應virtio, -
qxl對應qxl, -
vmwgfx對應vmware(qemu) 和vmvga(libvirt), -
cirrus對應cirrus。
-
-
VirtualBox 顯示控制器:
-
vmwgfx對應 VMSVGA, -
vboxvideo對應 VBoxVGA 或 VBoxSVGA。
-
根據使用的 initramfs 生成器,具體的配置方法略有不同。
mkinitcpio
使用樹內模塊時,可以將 kms 加入到 /etc/mkinitcpio.conf 的 HOOKS 數組中(自 mkinitcpio v33 起為默認設置),或將模塊名稱加入 MODULES 數組。
對於樹外 NVIDIA 模塊,必須將模塊的名字加入到 MODULES 數組中,如下所示:
/etc/mkinitcpio.conf
MODULES=(... nvidia nvidia_modeset nvidia_uvm nvidia_drm ...)
如果你在使用 #強制設置顯示模式與 EDID 的方法,則也需要將選定的文件集成到 initramfs 去:
/etc/mkinitcpio.conf
FILES=(/usr/lib/firmware/edid/your_edid.bin)
完成這一切後,重新生成 initramfs。
Booster
如果您在使用 Booster,可通過以下的方式改變設置來加載需要的模塊。
/etc/booster.yaml
modules_force_load: i915
如果您在使用 #強制設置顯示模式與 EDID 的方法,則也需要將選定的文件集成到 Booster 鏡像中:
/etc/booster.yaml
extra_files: /usr/lib/firmware/edid/your_edid.bin
之後,重新生成 Booster 鏡像。
Dracut
Dracut 可通過 --force_drivers 命令行選項,或配置文件中的 force_drivers+="" 設置,在 initramfs 階段使用 modprobe 提前加載驅動。例如:
/etc/dracut.conf.d/myflags.conf
# ... force_drivers+=" amdgpu " # ...
如果您在使用 #強制設置顯示模式與 EDID 的方法,則也應包含自定義文件:
/etc/dracut.conf.d/myflags.conf
install_items+=" /usr/lib/firmware/edid/your_edid.bin "
之後,重新生成 Dracut 鏡像。
問題解決
字體太小
Linux 控制台#字體介紹了如何在終端中使用大字體。軟體倉庫中的 (terminus-font包) 字體提供了很多字號,比如更大一些的 ter-132b。
或者,可以#禁用 KMS 以切換為更低的解析度,使得字體外觀顯得更大一些。另一種選擇是 KMSCON。
強制設置顯示模式與 EDID
如果無法自動配置您本機的解析度,或者根本無法偵測到顯示器;您的顯示器很有可能沒有或發送了破損的 EDID 文件。內核將嘗試捕獲這種情況並設置為某一通用解析度。
如果您擁有貴顯示器的 EDID 文件,您只需明確地強制設置即可(詳見下文)。但是,您在大多數情況下可能無法直接取得一個健全的 EDID 文件。您可能需要提取現有 EDID 文件中的信息並試圖修復它,從而獲得了一個新的 EDID 文件。
在內核編譯期間,可以通過遵循 上游文檔 來生成用於各種解析度和配置的新EDID二進製文件(另請參見 此處 的簡短指南)。 這篇文章 也詳細概述了其他解決方案。在大多數情況下,提取現有文件比較容易。例如從Windows下的驅動程序中提取EDID,如果您的顯示器在那裡運行良好。或者您可以使用來自 read-edid包 包的 get-edid(1) 命令,從具有相同設置的類似顯示器中提取。可以從 /sys/class/drm/*/edid 中查找一下。
在您的EDID準備就緒後,請將它放置於特定的文件夾。例如一個在 /usr/lib/firmware/ 下名為 edid 的文件夾,您可以將您的二進制文件放入其中。
請在內核參數中設置下述參數來在啟動時加載:
drm.edid_firmware=edid/你的edid.bin
用下述參數來設定特定的連接器:
drm.edid_firmware=VGA-1:edid/你的edid.bin
如果你希望設置多個 edid 文件,用下面的參數:
drm.edid_firmware=VGA-1:edid/你的edid.bin,VGA-2:edid/你的另一个edid.bin
如果您要進行#KMS 早啟動,則必須在 initramfs 中包含自定義 EDID 文件,否則可能會遇到問題。
啟動後,也可以通過寫入 /sys/module/drm/parameters/edid_firmware 修改 drm.edid_firmware 參數:
# echo edid/你的edid.bin > /sys/module/drm/parameters/edid_firmware
此更改只會對新連接的顯示器生效;已經連接的顯示器會繼續使用原來的 EDID 設置。對於外接顯示器,重新插拔即可使更改生效。
如果內核不處於鎖定模式,可以使用 debugfs 在啟動後加載 EDID,而不必通過內核命令行參數。這對於更換連接器上的顯示器或測試 EDID 特別有用。準備好上述 EDID 文件後執行:
# cat correct-edid.bin > /sys/kernel/debug/dri/0/HDMI-A-2/edid_override
若要取消覆蓋:
# echo -n reset > /sys/kernel/debug/dri/0/HDMI-A-2/edid_override
如果顯示器支持熱插拔,還可以觸發熱插拔事件,讓顯示器使用剛剛加載的新 EDID(例如寫入 edid_override 的 EDID),無需實際重新插拔顯示器或重新啟動:
# echo 1 > /sys/kernel/debug/dri/0/HDMI-A-2/trigger_hotplug
Forcing modes
來自 nouveau wiki:
用內核命令行可以強制設置使用的模式。但是 DRM 內核選項的文檔很少,使用的方法位於:
- https://docs.kernel.org/fb/modedb.html
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/gpu/drm/drm_fb_helper.c
格式:
video=<driver>:<conn>:<xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
-
<driver>:指定啟動時的視頻模式。 -
<conn>:指定視頻連接類型,例如 VGA、DVI、HDMI 等;可通過/sys/class/drm/查看可用連接器。 -
<xres>:水平解析度(像素)。 -
<yres>:垂直解析度(像素)。 -
[M]:使用 VESA 協調視頻時序(CVT)計算模式時序,而不是從資料庫中查找模式。 -
[R]:在使用 CVT 時為數字顯示器啟用減少消隱時間計算,縮短水平及垂直消隱間隔以節省帶寬。 -
[-<bpp>]:顏色深度,即每像素位數(例如-24表示 24 位色)。 -
[@<refresh>]:刷新率(Hz)。 -
[i]:啟用隔行掃描模式。 -
[m]:在 CVT 計算中添加邊距(水平解析度的 1.8%,向下取整為 8 的倍數;垂直解析度的 1.8%)。 -
[e]:強制啟用輸出。 -
[D]:強制啟用數字輸出(例如 DVI-I 連接器)。 -
[d]:強制關閉輸出。
可以使用多個 video= 設置不同輸出的解析度,例如要強制 DVI 使用 1024x768 85 Hz,同時禁用 TV-out:
video=DVI-I-1:1024x768@85 video=TV-1:d
也可以在模式之後用逗號分隔並傳入其他選項:
video=DVI-I-1:720x480,rotate=180
有效選項包括:
-
margin_top、margin_bottom、margin_left、margin_right(整數):邊距的像素數,通常用於處理電視的過掃描問題。 -
reflect_x(布爾值):沿 X 軸進行鏡像反射。 -
reflect_y(布爾值):沿 Y 軸進行鏡像反射。 -
rotate(整數):將初始 framebuffer 旋轉指定角度,可用值為 0、90、180、270。 -
tv_mode:模擬電視制式,可用值包括 "NTSC"、"NTSC-443"、"NTSC-J"、"PAL"、"PAL-M"、"PAL-N" 或 "SECAM"。 -
panel_orientation:可用值為 "normal"、"upside_down"、"left_side_up" 或 "right_side_up"。僅適用於 KMS 驅動,用於設置 KMS 連接器的 "panel orientation" 屬性,向 KMS 用戶提供顯示面板方向的提示。
要獲取當前連接器的狀態,使用下面命令:
$ for p in /sys/class/drm/*/status; do con=${p%/status}; echo -n "${con#*/card?-}: "; cat $p; done
DVI-I-1: connected HDMI-A-1: disconnected VGA-1: disconnected
禁用 KMS
有時需要禁用 KMS。只需在內核參數中加入 nomodeset 即可,設置方法請閱讀內核參數頁面。
使用 nomodeset 內核參數的同時,Intel 卡需要添加 i915.modeset=0,Nvidia 卡需要添加 nouveau.modeset=0。Nvidia Optimus 雙顯卡系統,需要添加三個內核參數:
nomodeset i915.modeset=0 nouveau.modeset=0