0 A.D. 字体与渲染问题排查笔记:Wayland 下的双层故障
这是一次在 Arch Linux + Hyprland + Wayland 环境下调试 0 A.D. 的记录。表面上看起来是字体渲染问题,但实际上涉及到显示协议、输入处理、渲染后端和字体 fallback 三个独立层面。
环境
- Arch Linux
- Hyprland + Wayland
- 0 A.D. 0.28.0
- Mesa 26.0.4
- Intel UHD Graphics 615
症状
0 A.D. 能启动,但 UI 文字显示为小方块带叉号。
有两个独立的可见问题:
- 原生 Wayland 下,游戏 UI 无法可靠点击。
SDL_VIDEODRIVER=x11 0ad下点击正常,但中文 UI 文字仍显示为方块。
关键线索来自游戏启动后的画面:同一个对话框里英文文字渲染正常,中文菜单标签和翻译后的 UI 字符串损坏。
这意味着不是全局字体渲染故障,而是特定的 CJK 字形选择/fallback 问题。
最终修复
用户配置:
1fonts.default = "SourceHanSansCN-Regular.otf", "LinBiolinum_Rah.ttf", "FreeSans.ttf"
2fonts.sans.regular = "SourceHanSansCN-Regular.otf", "LinBiolinum_Rah.ttf", "FreeSans.ttf"
3fonts.sans.bold = "SourceHanSansCN-Bold.otf", "LinBiolinum_RBah.ttf", "FreeSansBold.ttf"
4fonts.sans.italic = "SourceHanSansCN-Regular.otf", "LinBiolinum_RIah.ttf", "FreeSansOblique.ttf"
5rendererbackend = "vulkan"
文件:
1/home/alice/.config/0ad/config/user.cfg
用户桌面启动器覆盖:
1Exec=env SDL_VIDEODRIVER=x11 0ad %F
文件:
1/home/alice/.local/share/applications/0ad.desktop
字体覆盖修复中文文字。SDL_VIDEODRIVER=x11 覆盖避开 Wayland 输入/点击问题。
常用路径
0 A.D. 可执行文件包装器:
1/usr/bin/0ad
真正的引擎可执行文件:
1/usr/bin/pyrogenesis
系统桌面文件:
1/usr/share/applications/0ad.desktop
用户桌面覆盖:
1/home/alice/.local/share/applications/0ad.desktop
用户配置:
1/home/alice/.config/0ad/config/user.cfg
默认配置:
1/usr/share/0ad/data/config/default.cfg
运行时日志:
1/home/alice/.local/state/0ad/log/mainlog.html
2/home/alice/.local/state/0ad/log/interestinglog.html
3/home/alice/.local/state/0ad/log/system_info.txt
4/home/alice/.local/state/0ad/log/userreport_hwdetect.txt
游戏数据包:
1/usr/share/0ad/data/mods/mod/mod.zip
2/usr/share/0ad/data/mods/public/public.zip
使用过的命令
检查基本安装和版本:
1pacman -Q 0ad 0ad-data mesa vulkan-intel vulkan-icd-loader
20ad -version
检查会话类型:
1printf 'XDG_SESSION_TYPE=%s\nWAYLAND_DISPLAY=%s\nDISPLAY=%s\nDESKTOP_SESSION=%s\nXDG_CURRENT_DESKTOP=%s\n' \
2 "$XDG_SESSION_TYPE" "$WAYLAND_DISPLAY" "$DISPLAY" "$DESKTOP_SESSION" "$XDG_CURRENT_DESKTOP"
检查系统 fontconfig 能否找到相关字体:
1fc-match LinBiolinum_Rah.ttf
2fc-match 'Linux Biolinum'
3fc-match sans:lang=zh-cn
检查 0 A.D. 配置和日志:
1sed -n '1,80p' ~/.config/0ad/config/user.cfg
2rg -n "rendererbackend|Vulkan|OpenGL|font|Font|texture|Texture|ERROR|WARNING" \
3 ~/.local/state/0ad/log ~/.config/0ad ~/.local/share/0ad -S
列出 0 A.D. 自身数据压缩包内的字体:
1bsdtar -tf /usr/share/0ad/data/mods/mod/mod.zip | rg -i 'font|LinBiolinum|FreeSans|SourceHan|DejaVu'
读取压缩包内的字体纹理规则:
1bsdtar -xOf /usr/share/0ad/data/mods/mod/mod.zip fonts/textures.xml
日志显示的内容
默认配置加载:
1rendererbackend = "gl"
2fonts.default = "LinBiolinum_Rah.ttf", "FreeSans.ttf"
3fonts.sans.regular = "LinBiolinum_Rah.ttf", "FreeSans.ttf"
4fonts.zh.sans.regular = "SourceHanSansCN-Regular.otf"
编辑 user.cfg 后,日志显示覆盖已生效:
1Loaded config string "rendererbackend" = "vulkan"
2Vulkan available device: 'Intel(R) UHD Graphics 615 (AML-KBL)' Type: 1 Supported: Y
这意味着:
- Vulkan 确实已激活。
- 0 A.D. 识别到了 Intel GPU。
- 引擎以 0 错误 0 警告退出。
- 因此问题不是明显的缺失文件崩溃或启动失败。
截图改变了诊断方向:英文正常,中文损坏。
为什么最初的 GPU 理论看似合理
最初的假设
看到 UI 文字显示为方块时,第一个走进脑海的推断是:这是一个 GPU 渲染或图形驱动层面的问题。
理论内容大概是这样:字体显示为方块,可能是字形 atlas 上传到 GPU 时损坏了,或某个渲染后端和 Intel UHD 615 / Mesa 26 不兼容,导致纹理/字形渲染出错。如果是这种情况,切换渲染后端(如从 OpenGL 切到 Vulkan)或强制 X11 应该能解决问题。
为什么这个假设看似合理
起初症状看起来像图形问题:
- 字体显示为损坏的方块
- 系统是 Wayland + Intel UHD 615 + Mesa 26
- 0 A.D. 使用 GPU 渲染 UI 文字
- 0 A.D. 默认使用 OpenGL
- 0 A.D. 存在已知的 Wayland/渲染后端问题
0 A.D. 0.28 有多个渲染后端:
1rendererbackend = "gl"
2rendererbackend = "glarb"
3rendererbackend = "vulkan"
因此测试以下命令是合理的:
1SDL_VIDEODRIVER=x11 0ad -conf=rendererbackend:gl
2SDL_VIDEODRIVER=x11 0ad -conf=rendererbackend:glarb
3SDL_VIDEODRIVER=x11 0ad -conf=rendererbackend:vulkan
4LIBGL_ALWAYS_SOFTWARE=1 SDL_VIDEODRIVER=x11 0ad -conf=rendererbackend:gl
创建的临时辅助脚本:
1/home/alice/.local/bin/0ad-x11-gl
2/home/alice/.local/bin/0ad-x11-glarb
3/home/alice/.local/bin/0ad-x11-vulkan
4/home/alice/.local/bin/0ad-x11-software-gl
四种后端中文仍然损坏。这个结果排除了纯 GPU 后端问题。
关键概念
SDL
SDL 是 0 A.D. 用于窗口创建、输入和其他面向操作系统任务的跨平台层。
在 Linux 上,SDL 可以通过不同的视频驱动创建窗口,包括 Wayland 和 X11。
此命令强制 SDL 使用 X11:
1SDL_VIDEODRIVER=x11 0ad
在这个案例中,强制 X11 修复了点击/输入问题。
Wayland 与 X11
Wayland 和 X11 是显示服务器协议。
应用程序不直接向物理屏幕绘制。它们通过显示栈创建窗口。
在 Wayland 桌面上,游戏可能通过以下方式运行:
- 原生 Wayland
- XWayland,让 X11 应用程序在 Wayland 会话内运行
实用的简单规则:
- 如果游戏在 Wayland 下能打开,但鼠标点击、焦点、全屏或窗口位置损坏,尝试
SDL_VIDEODRIVER=x11。
OpenGL
OpenGL 是一种图形 API。游戏通过 OpenGL 驱动向 GPU 发送绘制命令。
0 A.D. 的默认配置使用:
1rendererbackend = "gl"
这意味着现代 OpenGL/GLSL 渲染器。
glarb
glarb 是 0 A.D. 使用传统 ARB 风格着色器的旧版 OpenGL 后端。
当新版 OpenGL 着色器路径存在驱动 bug 时,它可用作兼容性回退。
Vulkan
Vulkan 是一种较新的底层图形 API。
0 A.D. 有 Vulkan 渲染器。它可以避开一些 OpenGL 特定的驱动问题,但它仍然是 GPU 渲染路径。
在这台机器上,Vulkan 正确初始化:
1Vulkan available device: 'Intel(R) UHD Graphics 615 (AML-KBL)'
Mesa
Mesa 是 Intel 和 AMD GPU 在 Linux 上使用的开源图形驱动栈。
对于 Intel 显卡,Mesa 提供游戏使用的 OpenGL 和 Vulkan 驱动实现。
Mesa bug 可能表现为:
- 损坏的纹理
- 缺失的 UI 元素
- 着色器伪影
- 损坏的字形 atlas
- 仅在某一个渲染后端崩溃
纹理(Texture)
纹理是存储在 GPU 内存中的图像。
游戏不仅将纹理用于墙壁、地形和单位,也用于 UI 元素和字体。
字体 atlas / 字形 atlas
许多游戏不会每帧都直接请求操作系统绘制文字。
相反,引擎:
- 加载字体文件
- 将需要的字形栅格化为位图图像
- 把这些字形图像打包进纹理 atlas
- 需要文字时绘制 atlas 的片段
如果 atlas 上传到 GPU 的过程损坏,所有文字看起来都可能损坏。
如果选定的字体缺少需要的字形,只有那些字符会渲染为缺失字形方块。
本案例是第二种情况:英文字形存在,中文字形在选定的默认字体栈中不存在。
字体 fallback
字体 fallback 的意思是"如果第一个字体不包含这个字符,尝试另一个字体"。
0 A.D. 默认的 sans 字体栈是:
1fonts.sans.regular = "LinBiolinum_Rah.ttf", "FreeSans.ttf"
这对拉丁文字足够,但对中文不够。
0 A.D. 也自带:
1SourceHanSansCN-Regular.otf
2SourceHanSansCN-Bold.otf
对于本次安装,将 SourceHanSansCN 强制放到 default/sans 字体栈的最前面修复了中文 UI 文字。
思考框架
1. 分离症状
不要把所有可见问题合并为一个根本原因。
这里至少有两个:
- Wayland 下的输入/点击失败
- 缺失的中文字形
不同的测试将它们隔离:
SDL_VIDEODRIVER=x11修复了点击- 渲染后端更换没有修复中文文字
- CJK 字体覆盖修复了中文文字
2. 检查执行路径
追问:
- 实际启动的是什么命令?
- 桌面启动器与终端命令是否不同?
- 是否存在包装脚本?
- 真正的二进制文件在哪里?
对于 0 A.D.:
1/usr/bin/0ad -> 包装器
2/usr/bin/pyrogenesis -> 真正的引擎
桌面文件原本运行:
1Exec=0ad %F
修复后的用户覆盖运行:
1Exec=env SDL_VIDEODRIVER=x11 0ad %F
3. 阅读应用程序自身的日志
对于 0 A.D.,从这里开始:
1~/.local/state/0ad/log/mainlog.html
2~/.local/state/0ad/log/interestinglog.html
搜索:
1ERROR
2WARNING
3rendererbackend
4Vulkan
5OpenGL
6font
7texture
日志可以确认配置编辑是否真正生效。
4. 从应用程序的视角验证资源
系统 fontconfig 可能找到某种字体,但游戏可能不会将系统 fontconfig 用于其 UI 字体。
在本案例中,0 A.D. 在以下位置自带字体:
1/usr/share/0ad/data/mods/mod/mod.zip
所以 fc-match 有用,但不是决定性的。
决定性问题是:
10 A.D. 本身为正在使用的 UI 别名加载哪些字体文件?
5. 使用 A/B 测试来逐层消除
有效的渲染测试:
1SDL_VIDEODRIVER=x11 0ad -conf=rendererbackend:gl
2SDL_VIDEODRIVER=x11 0ad -conf=rendererbackend:glarb
3SDL_VIDEODRIVER=x11 0ad -conf=rendererbackend:vulkan
4LIBGL_ALWAYS_SOFTWARE=1 SDL_VIDEODRIVER=x11 0ad -conf=rendererbackend:gl
解读:
- 如果只有 Wayland 损坏,怀疑 SDL/Wayland/窗口/输入。
- 如果只有一个渲染器损坏,怀疑该渲染后端或 GPU 驱动路径。
- 如果软件渲染修复了它,怀疑 GPU/Mesa。
- 如果所有渲染器都显示相同的缺失字符但其他文字正常,怀疑字体选择/fallback。
6. 让现场观察影响判断模型
不要依赖记忆里的模糊印象。重新打开应用程序,仔细看实际渲染结果:
- 英文正文文字渲染正确。
- 中文 UI 文字没有。
这一个现场观察就压过了最初的 GPU 理论。
好的调试循环会在视觉证据变得更具体时更新假设。
类似问题的实用检查清单
- 从终端启动并收集日志。
- 确认会话类型:
1echo "$XDG_SESSION_TYPE"
- 如果 Wayland 输入/窗口行为异常,尝试:
1SDL_VIDEODRIVER=x11 0ad
- 在以下位置确认渲染后端:
1~/.local/state/0ad/log/mainlog.html
- 尝试渲染后端:
10ad -conf=rendererbackend:gl
20ad -conf=rendererbackend:glarb
30ad -conf=rendererbackend:vulkan
- 如果文字损坏,检查是所有文字损坏还是仅某种语言/文字。
- 如果只有中文/日文/韩文文字损坏,检查配置的 UI 字体栈。
- 优先使用应用级配置覆盖,而不是更改系统包。
当前工作状态
使用:
1SDL_VIDEODRIVER=x11 0ad
或在用户桌面覆盖安装后从应用菜单启动。
当前的持久化修复:
- X11 SDL 启动路径以获得可用的 UI 输入
- Source Han Sans CN 放在 0 A.D. default/sans 字体栈首位