内核模式设置
Kernel Mode Setting (KMS) 是一种在内核空间而不是用户空间设置显示分辨率和深度的技术。
Linux 内核的 KMS 实现支持帧缓冲区的原生分辨率,并允许即时切换控制台(tty)。KMS 还支持更新的技术(如 DRI2),这有助于减少画面瑕疵并提高 3D 性能,甚至支持内核空间的节能功能。
背景
以前,显卡设置是 X 服务器的工作。因此,在 虚拟控制台 中实现精美的图形并不容易。此外,每次从 X 切换到虚拟控制台(Ctrl+Alt+F2)时,服务器都必须将显卡控制权交给内核,这很慢并会导致闪烁。当控制权交还给 X 服务器时(当 X 在 VT7 中运行时为 Alt+F7),也会发生同样的“痛苦”过程。
通过 Kernel Mode Setting (KMS),内核现在能够设置显卡模式。这使得启动画面、虚拟控制台和 X 之间的快速切换成为可能,等等。
配置
首先,请注意,对于您使用的任何方法,都应始终禁用
- 您 引导加载程序 中的任何
vga=选项,因为它们会与 KMS 启用的原生分辨率冲突。 - 启用与驱动程序冲突的帧缓冲区的任何
video=行。
Late KMS start
Intel、Nouveau、ATI 和 AMDGPU 驱动程序已自动为所有芯片组启用 KMS,因此您无需执行任何操作。
专有的 NVIDIA 驱动程序支持 KMS(自 364.12 起),需要手动启用。
Early KMS start
KMS 通常在initramfs 阶段之后初始化。然而,也可以在 initramfs 阶段启用 KMS。将所需的显卡驱动模块添加到 initramfs 配置文件中。
amdgpu用于 AMDGPU,或在使用旧版 ATI 驱动程序时使用radeon。i915用于 Intel 显卡。nouveau用于开源 Nouveau 驱动程序。nvidia nvidia_modeset nvidia_uvm nvidia_drm用于树外 (out-of-tree) NVIDIA 驱动程序。有关详细信息,请参阅 NVIDIA#DRM kernel mode setting。
mgag200用于 Matrox 显卡。- 取决于所使用的 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 的配置说明因您使用的 initramfs 生成器而略有不同。
mkinitcpio
对于树内模块,请确保 kms 已包含在 /etc/mkinitcpio.conf 的 HOOKS 数组中(自 mkinitcpio v33 起即为默认设置)。
对于树外模块,请将模块名称放在 MODULES 数组中。例如,要为 NVIDIA 显卡驱动启用早期 KMS:
/etc/mkinitcpio.conf
MODULES=(... nvidia nvidia_modeset nvidia_uvm nvidia_drm ...)
intel_agp 可能导致从休眠恢复时出现问题(显示器无信号)。有关详细信息,请参阅 [3]。如果您使用#强制模式和EDID 方法,您还应该将自定义文件嵌入 initramfs 中。
/etc/mkinitcpio.conf
FILES=(/usr/lib/firmware/edid/your_edid.bin)
Booster
如果您使用 Booster,可以通过以下配置更改加载所需模块:
/etc/booster.yaml
modules_force_load: i915
如果您使用#强制模式和EDID 方法,您还应该将自定义文件嵌入到您的 booster 镜像中。
/etc/booster.yaml
extra_files: /usr/lib/firmware/edid/your_edid.bin
Dracut
Dracut 通过其 --force_drivers 命令或 force_drivers+="" 配置条目行,支持早期加载(在 initramfs 阶段,通过 modprobe)。例如:
/etc/dracut.conf.d/myflags.conf
# ... force_drivers+=" amdgpu " # ...
故障排除
我的字体太小了
有关如何更改控制台字体以使用大字体的说明,请参阅 Linux console#Fonts。Terminus 字体(terminus-font)有多种尺寸可选,例如 ter-132b 尺寸更大。
或者,禁用 modesetting 可能会切换到较低的分辨率,使字体看起来更大。
强制模式和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/your_edid.bin
为了仅将它应用于特定的连接器,请使用:
drm.edid_firmware=VGA-1:edid/your_edid.bin
如果要设置多个 edid 文件,请使用:
drm.edid_firmware=VGA-1:edid/your_edid.bin,VGA-2:edid/your_other_edid.bin
如果您正在进行 早期 KMS,则必须 将自定义 EDID 文件包含在 initramfs 中,否则会遇到问题。
drm.edid_firmware 参数的值也可以在启动后通过写入 /sys/module/drm/parameters/edid_firmware 来修改。
# echo edid/your_edid.bin > /sys/module/drm/parameters/edid_firmware
这只会对新插入的显示器生效,已插入的屏幕将继续使用其现有的 EDID 设置。但是,对于外部显示器,重新插拔它们足以看到效果。
要在启动后加载 EDID,如果内核未处于 锁定模式,您可以使用 debugfs 而不是内核参数。这对于交换连接器上的显示器或仅用于测试非常有用。一旦有了上述 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 中),这样您就不必物理上重新插拔显示器或重启了。
# echo 1 > /sys/kernel/debug/dri/0/HDMI-A-2/trigger_hotplug
强制模式
来自 nouveau wiki
- 可以在内核命令行上强制设置模式。不幸的是,DRM 情况下的 video 命令行选项文档非常少。关于如何使用它的零散信息可以在以下找到:
格式是:
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 Coordinated Video Timings (CVT) 来计算视频模式时序,而不是从数据库查找模式。[R]: 在使用 CVT 时,启用数字显示器的减少消隐计算。这会减少水平和垂直消隐间隔以节省带宽。[-<bpp>]: 指定颜色深度或每像素位数(例如,-24 表示 24 位颜色)。[@<refresh>]: 指定刷新率(Hz)。[i]: 启用隔行扫描模式。[m]: 为 CVT 计算添加边距(xres 的 1.8% 向下取整到 8 像素,yres 的 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(整数):将初始帧缓冲区旋转 x 度。有效值为 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 连接器上的“面板方向”属性,作为 KMS 用户的提示。
要获取连接器的名称和当前状态,您可以使用以下 shell 单行命令:
$ 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
禁用 modesetting
您可能出于各种原因希望禁用 KMS。要禁用 KMS,请将 nomodeset 添加为内核参数。有关更多信息,请参阅 Kernel parameters。
除了 nomodeset 内核参数外,对于 Intel 显卡,您需要添加 i915.modeset=0;对于 Nvidia 显卡,您需要添加 nouveau.modeset=0。对于 Nvidia Optimus 双显卡系统,您需要添加所有三个内核参数(即 "nomodeset i915.modeset=0 nouveau.modeset=0")。