ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

无显示器环境下Xorg花屏?用xorg.conf虚拟显示与Xvfb彻底解决

无显示器环境下Xorg花屏?用xorg.conf虚拟显示与Xvfb彻底解决 先说我遇到的实际场景。一台国产工控机装的麒麟系统 2403 版本现场没有接显示器我通过 Xorg x11vnc 远程桌面过去看。结果远程屏幕上一片花屏满屏色块鼠标移动还能看到残影但画面完全没法辨认。第一反应是 VNC 传输坏了或者网络丢包严重后来排查了一圈才发现问题根本不在 VNC而是这台机器在没有显示器的环境下Xorg 自己就把画面渲染坏了。这个案例在国产工控机上非常典型尤其是银河麒麟 V10 SP1 2403 这种新版本内核和显卡驱动的组合对无头环境支持得不够稳。我在网上也看到不少人问“Ubuntu 安装花屏”、“m3u8 视频下载为什么是花屏”其实“花屏”这个词在不同场景下指的东西完全不一样——有的是解码问题有的是渲染问题有的是传输问题。这篇文章只聊一件事在无显示器环境下Xorg 渲染输出的画面本身就是花的x11vnc 只是把这个花的画面原样传了出来。所以问题的源头在于 Xorg 的显示配置而不是 VNC 链路。文章会从问题原理讲起再给出一套在麒麟 2403 上实测有效的 xorg.conf 虚拟显示器配置方案最后补一个 Xvfb 兜底方案以及我踩过的几个坑。适合正在做国产化设备远程运维、无头工控机部署、或者被 VNC 花屏折磨的运维和嵌入式工程师参考。1. 先搞清问题无显示器环境下 Xorg 为什么会输出花屏/色块1.1 现象描述花屏不是在传输环节产生的如果你用 VNC 连一台有正常显示器的机器画面是好的拔掉显示器再通过 x11vnc 连接画面却变成了花屏和色块最大的嫌疑就是 Xorg 本身。x11vnc 做的是非常“笨”的事情——它直接读取 X 服务器已经绘制好的帧缓冲framebuffer把这块内存里的像素数据编码成 VNC 协议发出去。它不参与任何 3D 渲染也不重新绘制图形更不会对画面做二次加工。也就是说x11vnc 是一个“搬运工”它从 Xorg 手里拿到什么画面远程客户端看到的就是什么画面。所以当你看到花屏时先不要怀疑 x11vnc 的马赛克式花图那种通常是 JPEG 压缩异常或者网络粘包也不要怀疑 VNC Viewer 的解码错误。最直接的判断方法是在工控机上截一张图用 scp 拉回来本地看。如果本地看到的图片就是花的说明 Xorg 渲染输出就已经是花屏了跟 VNC 传输链路完全无关。这一步排查能帮你省下大量时间。1.2 根本原因显卡拿不到显示器的 EDID 信息无显示器环境下 Xorg 花屏根子在于 EDIDExtended Display Identification Data扩展显示标识数据。真实显示器通过 I2C 总线向显卡提供 EDID 数据里面包含了显示器的厂商、型号、物理尺寸、支持的分辨率列表、刷新率范围、像素时钟等关键参数。显卡驱动启动时会先读取 EDID根据这些参数决定输出什么分辨率、什么刷新率、用什么像素时钟然后初始化对应的显示输出通道。一旦没有显示器显卡读不到 EDID驱动就进入“盲猜”模式。很多驱动在这种情况下默认选择了一个驱动内部预设的 mode但和实际主板上的视频输出接口不匹配像素时钟算错导致行场同步信号偏移画面就会出现横向撕裂、斜条纹、色块颜色深度判断错误比如按 16bit 输出但前端颜色映射是 24bit造成色块和颜色错乱显示输出通道选错数字信号实际走的是 HDMI驱动却按 VGA 模拟信号处理。这一系列“盲猜”的结果就是渲染出来的画面本身就是乱的花屏、色块、横纹、晃动的 RGB 噪点都可能出现。这一现象在 Ubuntu 的某些笔记本外接屏、迷你主机接电视的场合也会遇到其实就是无 EDID 或 EDID 读取失败导致的和系统品牌没关系只是麒麟系统在国产工控机上遇到得更频繁。1.3 为什么国产工控机更容易踩这个坑国产工控机有几个特点让这个问题被放大了第一硬件平台多样化。国产工控机可能用兆芯、飞腾、龙芯或者各种国产 GPU 芯片每家的显示控制器实现差异很大。有的芯片在无显示器环境下能自己生成一份虚拟 EDID有的直接摆烂连输出 mode 都是错的。不同主板之间的 Layout 也不一样HDMI 和 VGA 的检测机制不同导致无头场景表现天差地别。第二BIOS/固件默认配置不适合服务器式运维。消费级主板通常默认开启“板载显卡优先输出”即使没有显示器也会尝试输出一个信号。但工控机的的 BIOS 往往做了定制可能默认关闭了显卡输出或者在未检测到面板时直接把显示控制器挂起到异常状态。第三麒麟 V10 SP1 2403 这种新版本系统内核和 Xorg 的版本都比老系统新驱动改动很大。新的 modesetting 驱动使用内核的 DRM 接口和老旧的 radeon/nouveau 等驱动在无 EDID 时的行为完全不同。配置不对花屏方式也千奇百怪。明白这一点后解决思路就很清晰了想办法给 Xorg 一个“虚拟的显示器信息”让显卡驱动认为它接了一台正常的、支持固定分辨率的显示器从而按照我们指定的参数去初始化显示输出。2. 解决思路总览给 Xorg 一个“看不见的显示器”2.1 核心思路用 xorg.conf 伪造一个稳定可信的显示环境Xorg 在启动时会读取配置文件来决定显示输出的参数。在没有显示器的情况下我们可以在配置里手动指定显卡驱动使用哪个显示输出接口默认分辨率和刷新率颜色深度虚拟屏幕尺寸允许大于物理屏幕用于多桌面。这套配置本质上是在“骗”显卡驱动让它以为自己接了一台支持特定参数的显示器一台“看不见的显示器”。驱动拿到这些参数后就不会再去猜而是老老实实按配置文件初始化输出。Xorg 配置的生效优先级非常高通常会覆盖驱动自动探测的结果。前提是你的配置语法正确、对应的显卡驱动模块能被正确加载。2.2 两条路线对比修 Xorg vs 换 Xvfb在处理麒麟无头花屏时有两条主流路线路线 A修 Xorg 配置。就是这台工控机本身跑的是完整桌面环境我们希望保留原有桌面和窗口管理器通过 Xorg x11vnc 远程看到同一个桌面。这种情况必须给 Xorg 配一个虚拟显示。路线 B换用 Xvfb。如果这台机器只需要跑图形程序不需要完整桌面直接用 XvfbX Virtual Framebuffer创建一个纯内存的虚拟显示。Xvfb 不依赖任何物理显卡在内存里模拟一个 framebuffer渲染结果直接通过 VNC 传出去天然不会花屏。但是 Xvfb 没有 GPU 加速也不会有桌面动画特效适合工控软件这种偏简单界面的场景。我个人的建议是优先修 Xorg 配置因为很多麒麟工控机上跑的是客户自己的桌面应用换 Xvfb 意味着桌面组件都变了应用兼容性风险更大。只有当 Xorg 怎么配都配不出正常画面时再考虑 Xvfb 做兜底。2.3 方案选型背后的取舍逻辑为什么不是直接调 x11vnc 的参数因为 x11vnc 的很多参数比如 -scale、-ncache、-xrandr主要影响 VNC 协议层的编码和缩放解决不了“渲染源就是花的”这个根本问题。用再好的编码器也拯救不了一帧本身就是乱码的画面。也有一种临时办法是在 Xorg 启动后动态插入一个 HDMI/DP 诱骗头让显卡检测到物理显示设备。但这需要额外采购硬件而且工控机的接口可能已经占用了部署也不优雅。用 xorg.conf 解决是最经济、可复制的方案。3. 实操在麒麟 2403 上配置 Xorg 虚拟显示彻底解决花屏3.1 确认当前环境和显卡型号动手之前先把机器的显卡信息摸清楚。在 Rocky 或纯命令行终端里执行lspci | grep -iE vga|display|3d我在这台工控机上看到的结果是这样的01:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Oland XT [Radeon HD 8570 / R7 240 OEM]说明用的是 AMD 的 Oland 核心显卡对应 Xorg 驱动是radeon或amdgpu。麒麟系统默认会加载amdgpu内核模块但 Xorg 层用的是 modesetting 还是 radeon需要看日志grep -i driver /var/log/Xorg.0.log | head -20在我的环境里日志显示用的是modesetting驱动。这说明系统走的是内核 DRM 接口而不是老的用户态 radeon 驱动。不同驱动xorg.conf 的关键选项写法会有差别这一步必须确认清楚。3.2 编写 xorg.conf核心参数讲解如果没有现成的 xorg.conf创建一个固定显示参数的文件即可。目录有两种放法我习惯放在/etc/X11/xorg.conf.d/下面以编号开头命名确保优先级高于默认配置。创建/etc/X11/xorg.conf.d/30-headless.conf内容如下Section Device Identifier HeadlessGPU Driver modesetting Option PrimaryGPU true EndSection Section Monitor Identifier HeadlessMonitor Option PreferredMode 1920x1080 HorizSync 30.0-83.0 VertRefresh 50.0-76.0 Modeline 1920x1080_60.00 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync vsync EndSection Section Screen Identifier HeadlessScreen Device HeadlessGPU Monitor HeadlessMonitor DefaultDepth 24 SubSection Display Depth 24 Modes 1920x1080_60.00 Virtual 1920 1080 EndSubSection EndSection几个关键点Driver 字段如果日志显示用的是 radeon这里就写radeon。也就是说先看Xorg.0.log再定不要照抄。Modeline这串数字定义了像素时钟、前后肩、同步脉冲宽度。直接使用 standard 1920x108060Hz 的详细时序即可这是标准 CEA-861 和 DMT 里都支持的时序。如果没有 Modeline很多驱动默认一个 1024x76860 的垃圾时序分辨率低且可能颜色深度也不对。Virtual 1920 1080定义 framebuffer 虚拟大小。如果你需要多个工作区或者某些工业软件需要更大的桌面可以把这里调大比如Virtual 2560 1080就能横向跨屏开两个窗口。但注意虚拟屏幕越大内存占用和 VNC 编码开销也越大在工控机上别盲目调大。DefaultDepth 24强制 24bit 真彩色。无头场景驱动经常错误地降级到 16bit这就是屏幕看起来色彩怪异、有带状色块、渐变色全变成条纹的直接原因。写成 24配合 VNC 客户端的自动颜色深度画面色彩就正常了。3.3 让 Xorg 加载配置并设置为默认启动配置文件放好后先验证语法有没有问题。Xorg 不会给我们一个“语法检查器”但可以通过手动启动 Xorg 来测试。在纯命令行模式下先切到 multi-user.target 或用 CtrlAltF2 切换到其他 tty执行sudo systemctl stop lightdm sudo Xorg -config /etc/X11/xorg.conf.d/30-headless.conf -verbose 2/tmp/xorg-test.log :1如果 Xorg 能正常停留在后台运行不报错退出说明配置可用。按 CtrlC 退出测试然后重启显示管理器sudo systemctl start lightdm因为我用的麒麟系统默认桌面管理器是 lightdm如果你那边是 gdm3 或 sddm就对应改成服务名。重启后在本地查看确认 Xorg 是否成功加载新配置。如果远程已经花屏了不要指望 VNC 能看到正常输出。这时候方式是通过 SSH 进入系统查看日志grep -iE \(EE\)|\(WW\)|using configuration|modeline|screen /var/log/Xorg.0.log只要看到() Using system config directory和() Using system config directory /usr/share/X11/xorg.conf.d这样的 Xorg 加载信息就知道配置文件被吃进去了。3.4 启动 x11vnc 并验证Xorg 本身正常后再用 x11vnc 接管显示。推荐用如下参数启动x11vnc -display :0 \ -auth guess \ -rfbport 5900 \ -forever \ -shared \ -noxdamage \ -ncache 10 \ -solid black \ -logfile /var/log/x11vnc.log参数说明-noxdamage关闭 X DAMAGE 扩展检测。麒麟系统上这个扩展经常误报区域变化导致 VNC 画面持续刷小块、花片关掉后编码更稳定。-ncache 10启用客户端缓存配合 VNC Viewer 的 Tight 编码能减少重新传输的数据量对于远程运维的弱网场景帮助很大。-solid black在连接建立时把桌面背景刷成纯色避免旧画布残影影响判断。-auth guess自动猜测 Xauthority 路径麒麟图形会话下很省事。启动后用 VNC Viewer 连接IP:5900此时远程应该直接看到正常桌面。我第一次在这台机器上成功看到桌面时特意切了几个窗口、开了一个视频播放器又用xrandr查看分辨率输出如下xrandr | grep * 1920x1080_60.00 60.00*分辨率也正确色彩也正常花屏问题彻底消失。整个过程从排查到解决大约花了 40 分钟其中 20 分钟都在读日志和确认驱动类型真正配置只用了 5 分钟。4. 备选方案Xvfb x11vnc 的无头显示方案4.1 什么时候需要备选方案Xorg 始终无法输出正常画面时并不是所有机器都能通过 xorg.conf 解决。我在另外一台飞腾平台的机器上遇到过更诡异的场景无论怎么配Xorg 一旦启动通过 x11vnc 看到的画面就是乱码日志里没有任何报错。查看了好久都没定位到具体原因最后走了 Xvfb 路线。另外如果工控机上跑的应用根本不依赖桌面环境只是需要一个 display 来给 Qt 或 OpenGL 程序画界面那么 Xvfb 反而是更轻量、更稳定的选择。它不碰物理显卡没有 EDID、没有驱动兼容性的坑是真正的“无头显示”标准方案。4.2 安装并启动 Xvfb麒麟系统基于 Debian 系直接安装sudo apt install xvfb x11vnc启动一个虚拟屏幕指定分辨率和色深注意这里的语法是宽x高x色深千万别漏了色深Xvfb :1 -screen 0 1920x1080x24 -nolisten tcp 启动后可以检查一下是否成功xdpyinfo -display :1 | head -10你会看到 Xvfb 的显示参数。重点注意第一行比如name of display: :1 version number: 11.0 vendor string: The X.Org Foundation如果输出正常说明 Xvfb 运行了。4.3 在这个虚拟显示上启动应用和 x11vncXvfb 起来后所有需要图形界面的程序都通过环境变量指到:1上启动DISPLAY:1 my-qt-app DISPLAY:1 firefox 然后启动 x11vnc 去抓取这个虚拟显示x11vnc -display :1 -rfbport 5901 -forever -shared -noxdamage -logfile /var/log/x11vnc-xvfb.log注意端口和之前不同避免冲突。远程连接IP:5901就能看到虚拟屏幕上的画面。用 Xvfb 的方式还有个额外好处就是机器上没有物理显示器接口和 Xorg 进程之间的争夺截屏也不会出现“当前会话未激活”的问题。我在这个方案上直接跑了连续几个月的定时截图任务稳定性很好。4.4 两种方案的取舍对比项目Xorg 虚拟显示Xvfb 虚拟显示GPU 加速支持取决于驱动不支持纯软件渲染桌面环境完整桌面、窗口管理器无桌面只能跑具体程序兼容性需匹配显卡驱动和 EDID 伪造不依赖任何显卡兼容性最好性能高适合复杂绘图较低但工控类简单界面完全够用配置复杂度需要理解 xorg.conf可能反复调试一行命令启动最简单适用场景必须保留原桌面/窗口只跑固定 GUI 程序、无桌面需求很多运维同事一上来就选 Xvfb发现客户要访问的桌面应用没了又要切回去。我做项目时的经验是先问清楚需求桌面必须保留就用 Xorg 方案只跑固定程序就 Xvfb少走弯路。5. 常见问题排查与踩坑实录5.1 问题速查表下面把我在麒麟 2403 和类似系统上排过的“花屏 / 色块 / 黑屏 / 卡顿”问题整理成速查表现象排查方向处置方法VNC 里画面花屏、色块本地截图也是花的Xorg 输出异常按第 3 节配置 xorg.conf 固定显示参数VNC 连接后黑屏x11vnc 抓到了错误 display确认实际显示编号ls /tmp/.X11-unix/指定-display :编号分辨率不对只有 1024x768 或更小虚拟屏幕配置未生效检查/var/log/Xorg.0.log是否加载了自定义 Modeline画面颜色怪异、渐变色块化颜色深度不正确强制DefaultDepth 24并在 x11vnc 参数里加-bgr233或让客户端自动适配鼠标移动时画面局部刷新成花斑X DAMAGE 扩展误报加-noxdamage并考虑加-ncache 10频繁断开或客户端反复重连VNC 服务崩溃看/var/log/x11vnc.log重点排查 auth 路径和共享模式长时间运行后分辨率自动变化驱动检测到 DPMS 或 EDID 变化在 xorg.conf 关掉 DPMSOption DPMS false这个表是我现场排查时的心法。逻辑顺序一定是先确认 Xorg 输出本身对不对再看 x11vnc 参数最后才怀疑 VNC 客户端。5.2 几个必踩的坑和我的处理经验第一个坑是盲目改驱动。有段时间我在另外一台 AST 显卡国产 GPU上折腾日志显示 modesetting 驱动加载失败系统自动退到了 fbdev 驱动结果分辨率锁死在 1024x768。我一度以为是配置写错了反复调整 xorg.conf 都没用。后来发现是那个国产 GPU 的内核模块没有正确加载需要先加载模块再启动 Xorg。遇到这类情况先看内核对显卡的支持情况再谈配置。第二个坑是忘掉 xorg.conf.d 的优先级。麒麟系统和 Ubuntu 一样/etc/X11/xorg.conf.d/里的文件按文件名排序加载数字越小的通常优先级越高。如果你放了一个10-nvidia.conf又放了一个30-headless.conf两者对于同一个 Section 的同一个 Option 可能互相覆盖。我习惯只用带明显前缀的文件比如30-避免和系统自带的冲突。第三个坑是-auth guess偶尔猜不准。麒麟系统默认 lightdm 运行图形会话时Xauthority 文件可能在/var/run/lightdm/root/:0x11vnc 直接启动时经常拿不到权限表现为连接上后立刻被断开或者黑屏。解决办法是用-auth显式指定x11vnc -display :0 -auth /var/run/lightdm/root/:0 ...更简单的办法是先用sudo -i切到 root 再启动 x11vnc能少踩很多权限坑。5.3 如何用日志快速定位问题根因麒麟系统下排查图形问题日志文件的优先级远高于各种搜索和猜。我每次定位的顺序是/var/log/Xorg.0.log—— Xorg 启动和配置加载日志重点看(EE)和(WW)行/var/log/x11vnc.log—— x11vnc 自身日志能看到它抓取的是哪个 displaydmesg | grep -i drm—— 内核显卡驱动的初始化情况DRM 子系统的报错有时比 Xorg 更早出现systemctl status lightdm | grep -i display—— 显示管理器的服务状态。一次典型的花屏现场排查我在 Xorg.0.log 里看到(WW) modeset(0): failed to set mode: Invalid argument (EE) modeset(0): failed to initialize random pixmap这就非常明确地指向modesetting 在无显示器环境下选不到合法 mode。加上 Modeline 并固定 Modes 后这两个日志都消失了。日志就是现场的最佳“见证人”养成先看日志的习惯能少走很多弯路。6. 个人经验总结与后续扩展折腾这么多国产工控机的显示问题我越来越认同一个判断标准无头环境下你能不能让显卡驱动像一个“正常显示器”一样工作决定了后续所有远程运维的体验。花屏、色块这种东西根源十有八九在 Xorg 的 EDID 和 mode 选择上。下次再遇到远程桌面花屏先截图拉回来看不要在 VNC 客户端上反复点重连——那是在浪费时间。另外想建议的是把这套配置写成一个自动化脚本无论换机器还是重新装机都能快速部署。我整理过一个简化版放在/usr/local/sbin/setup-headless-display.sh里核心逻辑就是检测显卡驱动类型、写入 xorg.conf、重启 lightdm、启动 x11vnc。配合 systemd 把 x11vnc 做成服务可以实现开机自动进入远程桌面工控机插电即用不需要任何人工介入。未来如果麒麟系统的新版本能在无 EDID 时自动生成可信的虚拟显示参数或者驱动作者们把无头模式的默认行为改得更稳健这类问题会越来越少。但在那之前掌握手写 xorg.conf 和 Xvfb 这两板斧就足够应对九成以上的国产工控机无头显示场景。实操中哪怕配置多折腾一小时也比现场拔显示器、插诱骗头或者重装系统省心得多。
返回列表