内核模式设置
内核 模式设置 (KMS) 是一种在内核空间而不是用户空间设置显示分辨率和深度的机制。
Linux 内核的 KMS 实现可以在帧缓冲中启用原生分辨率,并允许即时控制台 (tty) 切换。KMS 还启用了较新的技术(如 DRI2),这将有助于减少伪影和提高 3D 性能,甚至实现内核空间的节能。
背景
以前,显卡设置是 X 服务器的工作。因此,在 虚拟控制台 中实现华丽的图形并不容易。此外,每次从 X 切换到虚拟控制台(Ctrl+Alt+F2)时,服务器都必须将显卡控制权交给内核,这很慢并且会导致闪烁。当控制权交还给 X 服务器时(X 在 VT7 中运行时为 Alt+F7),也会发生同样“痛苦”的过程。
通过内核模式设置 (KMS),内核现在能够设置显卡模式。这使得在启动过程中、虚拟控制台和 X 之间进行快速切换时能够实现华丽的图形,等等。
配置
首先,请注意,对于您使用的任何方法,您都应始终禁用
- 您的 引导加载程序 中的任何
vga=选项,因为它们会与 KMS 启用的原生分辨率冲突。 - 任何启用了与驱动程序冲突的帧缓冲的
video=行。
延迟KMS启动
Intel、Nouveau、ATI 和 AMDGPU 驱动程序已经为所有芯片组自动启用了 KMS,因此您无需做任何事情。
专有的 NVIDIA 驱动程序支持 KMS(自 364.12 起),这需要 手动启用。
早期KMS启动
KMS 通常在 initramfs 阶段之后初始化。然而,也可以在 initramfs 阶段就已经启用 KMS。将 视频驱动程序 所需的模块添加到 initramfs 配置文件中
amdgpu用于 AMDGPU,或者在 O使用旧版 ATI 驱动程序时使用radeon。i915用于 Intel显卡。nouveau用于开源 Nouveau 驱动程序。nvidia nvidia_modeset nvidia_uvm nvidia_drm用于 OOTB 的 NVIDIA 驱动程序。有关详细信息,请参见 NVIDIA#DRM 内核模式设置。
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
对于 OOTB 模块,请确保 kms 已包含在 /etc/mkinitcpio.conf 的 HOOKS 数组中(自 mkinitcpio v33 起为默认值)。
对于 OOTB 模块,请将模块名称放在 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
然后 重新生成 booster 镜像。
Dracut
Dracut 通过其 --force_drivers 命令或 force_drivers+="" 配置项行,在 initramfs 阶段(通过 modprobe)启用早期加载。例如
/etc/dracut.conf.d/myflags.conf
# ... force_drivers+=" amdgpu " # ...
故障排除
我的字体太小了
有关如何更改控制台字体为大字体,请参见 Linux 控制台#字体。Terminus 字体(terminus-font)有多种尺寸可供选择,例如 ter-132b,它更大。
或者,禁用模式设置 可能会切换到较低分辨率,使字体显得更大。
强制模式和EDID
如果您的原生分辨率未自动配置,或者根本未检测到显示器,那么您的显示器可能不发送 EDID 文件,或者只发送一个不完整的 EDID 文件。内核会尝试捕获这种情况,并设置最典型的分辨率之一。
如果您有显示器的 EDID 文件,您只需显式强制它(见下文)。然而,大多数情况下,您无法直接访问一个可用的文件,因此有必要提取现有文件并修复它,或者生成一个新文件。
可以通过遵循 上游文档(也可在此 处找到简短指南)在内核编译期间生成各种分辨率和配置的新 EDID 二进制文件。其他解决方案的详细信息在此 文章中概述。在大多数情况下,提取现有文件更简单,例如,如果您的显示器在 Windows 下运行正常,您可能幸运地从相应驱动程序中提取 EDID,或者如果一个具有相同设置的类似显示器工作正常,您可以使用 get-edid(1) 命令,该命令来自 read-edid 包。您也可以尝试在 /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_override)的新 EDID,这样您就不必物理上重新插拔显示器或重新启动。
# 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>: 水平 O分辨率(以像素为单位)。<yres>: 垂直 O分辨率(以像素为单位)。[M]: 启用 VESA 协同视频定时 (CVT) 来计算视频模式定时,而不是从数据库查找模式。[R]: 使用 CVT 时,启用数字显示器的缩减消隐计算。这会减小水平和垂直消隐间隔以节省带宽。[-<bpp>]: 指定颜色深度或每像素位数(例如,-24 表示 24 位颜色)。[@<refresh>]: 指定刷新率(以 Hz 为单位)。[i]: 启用隔行扫描模式。[m]: 在 CVT 计算中添加 O边距(xres 的 1.8% 向下舍入到 8 像素,yres 的 1.8%)。[e]: 输出强制开启。[D]: 数字输出强制开启(例如 DVI-I 连接器)。[d]: 输出强制关闭。
您可以使用多次 video= 来 O覆盖多个输出的模式,例如,将 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
禁用模式设置
您可能因为各种原因想要禁用 KMS。要禁用 KMS,请将 nomodeset 添加为内核参数。有关更多信息,请参见 内核参数。
除了 nomodeset 内核参数之外,对于 Intel 显卡,您需要添加 i915.modeset=0;对于 Nvidia 显卡,您需要添加 nouveau.modeset=0。对于 Nvidia Optimus 双显卡系统,您需要添加所有三个内核参数(即 "nomodeset i915.modeset=0 nouveau.modeset=0")。