信创 2026/11/01 20:33

[肥鱼大战信创] ARM64 国产机成功运行《侠盗猎车手:罪恶都市》

既然已经切换到了信创机,至少 I/O 性能比之前那台只能用机械硬盘的老电脑要强太多。我们需要值班的时候很多,想着能不能装个游戏什么的。3A 对于这颗马良 GPU 来说是负担太大,于是就想到了在小学电脑机房里经常玩的罪恶都市,看着能不能在这台机器上跑。

本来想着让大肥鱼来攻坚 Wine 的,结果大肥鱼找到了一个开源项目reVC,能让罪恶都市在 Linux 上原生运行。一看,还有这好事。在罪吧找到了游戏本体和汉化包之后,就交给大肥鱼开干,结果还真能跑,帧数还很高。

说一下大肥鱼写的文里没提到的一点:汉化。因为reVC里的设置菜单里多出了一些原版游戏没有的设置项,而且汉化组的字库恰好还没包括这几个字,重新排列组合字库仍旧缺字,目前我这边的解决方案是,没有翻译文本的text不进行翻译,显示原本的英文。如果强行让他搞的话,游戏会在显示相关文字的时候直接崩溃。虽说也应该能让大肥鱼自己扩充字库,但出于性价比的考虑(设置菜单毕竟也不是经常翻的,而且没被翻译的部分基本都不会碰它,而且也影响不到游戏),所以说就直接让大肥鱼就这样将计就计了。

大肥鱼正在深度思考DeepSeek
已完成思考以下内容由 AI 生成

这篇文章记录了一个真实发生过的技术攻坚:在一台国产麒麟(ARM64)台式机上,把 2002 年的《侠盗猎车手:罪恶都市》从「5 帧幻灯片」救回到「1280×720 全程 60~88 帧」。

先看结论

国产麒麟 V10 ARM64 机器(华为擎云,GPU 是华为 Maleoon 920)上,GTA 罪恶都市靠开源重制引擎 reVC 跑到了 1280×720 / 57~88 FPS 的硬件加速。

整个故事里真正的难点只有一个:这颗 GPU 没有原生 OpenGL 驱动,只有 Vulkan。所以游戏必须通过一个叫 zink 的「翻译层」——把 OpenGL 命令实时翻译成 Vulkan 再交给 GPU。而麒麟的 Mesa 默认并不给陌生程序开 zink。捅破这层窗户纸之后,你会发现这其实是一条通用套路:老 Direct3D / OpenGL 游戏,在这类国产 ARM 机器上,本质都是「白名单 + 翻译层」两件事。


一、这台机器长什么样

项值
系统银河麒麟 V10 SP1,aarch64(ARM64)
桌面UKUI + KWin Wayland(应用实际跑在 XWayland 上,问题更少)
GPU华为 Maleoon 920(内核 DRM 驱动 hisi-dpu-drm)
关键系统包hw-maleoon-920、libzink-hisi、libgl1-mesa-dri 20.0.8-0kylin3k26.1
游戏GTA Vice City 原版数据 + reVC(re3 项目的 VC 重制引擎,开源 C++)

如果你手头的机器也是「麒麟 ARM + 华为擎云」,那这篇基本可以直接照搬;如果是别的国产 ARM 机型,思路一样,只是驱动包名可能不同。


二、先别急着动手:瓶颈到底在哪

接手这类任务时,我最大的一个教训是——第一步不是动手改,而是先判断性能瓶颈卡在渲染链路的哪一段。否则容易像我一样,在 FSR 上白白绕一大圈。

从游戏到 GPU,渲染只有三种可能:

  1. 软渲染 llvmpipe——纯 CPU 光栅化,老游戏最常见的「能跑但个位数帧」
  2. zink 硬件翻译——OpenGL → Vulkan,真正走 GPU(这次的目标)
  3. 原生 OpenGL 驱动——抱歉,这颗 GPU 根本没有

怎么判断自己在哪一种?看 renderer 字段就够了,一条命令或一行日志:

renderer=llvmpipe (LLVM x.x, 128 bits)   → 软渲染,问题在「根本没用到 GPU」
renderer=zink (Maleoon 920)              → 硬解正常,成功

这台机器默认就是 llvmpipe,罪恶都市只有 5~7 FPS。所以问题根本不是「游戏太重」,而是「GPU 完全闲置」。


三、核心机制:为什么默认是软渲染

麒麟在这类 ARM 机器上的 Mesa 布局,是一个经典的「双栈陷阱」,整件事的根子就在这:

  • 系统自带的 Mesa 是 20.0.8(libgl1-mesa-dri 等)。这个版本不认识 Maleoon 920,只能给你 llvmpipe 软渲染。
  • 华为另外提供了一个 libzink-hisi 包,里面是一套 Mesa 22.3.7,自带 zink 翻译器——能把 OpenGL 实时翻成 Vulkan 交给 Maleoon 920。
  • 但 Mesa 不会默认给所有程序都开 zink,而是通过 driconf 应用白名单(/usr/share/drirc.d/01-hisi.conf),按可执行文件名逐个放行。

这就解释了一个特别迷惑人的现象:glxgears 能硬解(它被写进了白名单),而你自己编译的 reVC 却只能软渲染——差别仅仅在于「可执行文件名在不在白名单里」。

把这一层想通,问题就从「玄学」变成了「白名单工程」。

下面这张图是整台机器上 OpenGL 到 GPU 的真实链路:

flowchart LR
    A["游戏 reVC<br/>(发出 OpenGL 3.2 调用)"] --> B{"Mesa 检查 driconf 白名单<br/>(按可执行文件名)"}
    B -->|"名字不在白名单"| C["llvmpipe 软渲染<br/>纯 CPU · 5~7 FPS"]
    B -->|"名字在白名单<br/>dri_driver=zink"| D["zink 翻译层<br/>(Mesa 22.3.7, libzink-hisi)"]
    D --> E["翻译成 Vulkan"]
    E --> F["Maleoon 920 GPU<br/>硬解 · 60~88 FPS"]
翻译层有一点点额外开销,但从实测看,在这颗 GPU 上完全不是瓶颈。

四、三步解法(可复制的通用套路)

第一步:让依赖栈保持干净

reVC 是动态链接的,运行时会 dlopen 系统里的 libGL。这一步最重要的教训是:

别让 LD_LIBRARY_PATH 指到旧的 Mesa 栈目录。

我一开始图省事,把启动器的 LD_LIBRARY_PATH 指到了某个旧依赖目录(里面带 Mesa 20.0.8),结果就算装了 zink 也照样软渲染——因为加载器优先命中了旧栈。正确做法是:把游戏所需的非 GL 依赖(比如 libglfw.so.3)就地复制进游戏目录,让 LD_LIBRARY_PATH 只指向游戏目录本身,GL 部分交给系统按白名单去选。

# 验证依赖无缺失(在设置了 LD_LIBRARY_PATH 的前提下)
LD_LIBRARY_PATH="$G" ldd "$G/reVC" | grep "not found"   # 应该没有输出

第二步:把可执行文件名加进 zink 白名单

最干净、最通用的做法是写用户级配置 ~/.drirc——不需要 root,也不碰系统文件:

<?xml version="1.0" standalone="yes"?>
<driconf>
    <device>
        <application name="reVC" executable="reVC">
            <option name="vblank_mode" value="0"/>
            <option name="dri_driver" value="zink"/>
        </application>
    </device>
</driconf>

三个要点:

  • executable 匹配的是可执行文件名,不是路径——所以一旦重编译改了名字,就要重新放行一次
  • dri_driver=zink 让 Mesa 强制走 zink;vblank_mode=0 把垂直同步的控制权交还给游戏
  • 一个 <device> 里可以塞多个 <application>(我就同时放了 reVC 和 java,后者给 Minecraft 用)

第三步:验证 renderer 已经切换成功

改完白名单重启游戏,看日志开头的 GL 信息:

[GLINFO] renderer=zink (Maleoon 920) | version=3.2 (Compatibility Profile) Mesa 22.3.7 | vendor=Collabora Ltd

只要 renderer=zink (Maleoon 920) 一出现,就说明 OpenGL 已经被翻译成 Vulkan、真正交给 GPU 了。这一瞬间,帧率从 5~7 直接跳到 60~90。


五、一个更值钱的思路:先测「性能天花板」

在纠结要不要上 FSR、要不要降分辨率之前,先关掉帧限制,测一下引擎的真实上限。这一步能帮你省下大量无效投入。

reVC 有个 FrameLimiter=1,默认把帧率锁在 30。我一开始看到的「30 FPS」,其实是这个限制,不是硬件瓶颈。把 FrameLimiter=0 后实测:

场景800×6001280×720
过场动画8073
街景62~6777
驾驶67~8857~80

结论一目了然:瓶颈在帧限制,不在填充率。所以正确方向是「提高分辨率」,而不是「FSR 把内部分辨率降下去再补回来」。我实测开 FSR 1.0 反而掉到 28~29 FPS——多出来的翻译和上采样开销得不偿失。

这条教训值得反复记住:先测上限,再谈优化。 很多人(包括一开始的我)一看帧率低就上 FSR、降分辨率,结果发现瓶颈压根不在渲染负载上。

六、FSR 为什么只能选 1.0

如果你确实需要超分辨率,那版本的选择几乎是被锁死的:

  • FSR 1.0:纯后处理(EASU 上采样 + RCAS 锐化),只需要颜色缓冲——老游戏都能用
  • FSR 2/3:需要深度缓冲 + 运动矢量 + 亚像素抖动,这些是 2002 年的 RenderWare 管线根本不提供的东西,硬塞等于重写整个渲染器

所以老游戏上 FSR 的答案固定是 1.0,而且前提是「填充率真的不够」,否则没有任何收益。


七、一路踩过的坑(症状 → 根因 → 解法)

这些是我在真机上一个个撞出来的,整理成表,方便你对照自查:

症状根因解法
帧率个位数走了 llvmpipe 软渲染见第四节的「白名单 + 干净依赖栈」
启动报 Cannot find desired video mode 闪退远程桌面(如向日葵)接管后,XWayland 只暴露当前分辨率一种模式,游戏找不到就退出选模式处加兜底:窗口模式下找不到匹配的独占模式,就直接用窗口模式 + 配置里的尺寸
屏幕设置页 SIGSEGV 崩溃上一个兜底让「当前分辨率」索引指到了窗口模式条目,而该条目被填成了空指针,绘制文本时解引用崩溃给窗口模式也生成描述文本。一个列表若有多处消费点,改一处必须查另一处
游戏里角色一直往左走远程软件注入了 keydown 却没发 keyup,X 层按键卡死(用 XQueryKeymap 能直接看到)断开远程后 xdotool keyup <键> 释放;这是远程软件的问题,不是游戏 bug
输入法吃掉 WASD中文输入法在游戏里拦截按键在焦点回调里用 fcitx-remote 检测并切成英文直通,失焦再恢复
鼠标被锁在窗口里出不去GLFW_CURSOR_DISABLED 抓取了指针加「Alt 临时释放 + 失焦释放 + 点回收回」的焦点回调

八、写给想复现的人:一条可迁移的方法论

把这套经验抽象成六步,几乎适用于所有「国产 ARM 机器上跑老 PC 游戏 / 老 OpenGL 程序」的场景——包括 Minecraft、各类 re3/reVC 重制引擎,甚至其他依赖 OpenGL 的桌面软件:

  1. 先判瓶颈 —— glxinfo -B 或日志里的 renderer 字段,确认是 llvmpipe 还是 GPU
  2. 理解双栈 —— 麒麟 ARM 机器上「系统 Mesa 太老 + 华为单独给 zink Mesa」,版本差异就是软/硬解的开关
  3. 白名单放行 —— 把可执行文件名写进 driconf(~/.drirc 或系统 drirc.d),设 dri_driver=zink
  4. 保依赖干净 —— LD_LIBRARY_PATH 别指向带旧 Mesa 的目录,非 GL 依赖就地放
  5. 先测上限 —— 关帧限制 / 垂直同步,确认真实瓶颈,再决定要不要 FSR 或降分辨率
  6. 验证闭环 —— 每次改动后看 renderer 字段 + 实际帧率,别凭感觉

给读者的自查清单(读完就能动手)

  • [ ] 你的机器是麒麟 ARM + 华为擎云(Maleoon 920)吗?不是的话,思路通用但包名要自己查
  • [ ] 先跑 glxinfo -B,看当前是 llvmpipe 还是 zink
  • [ ] 确认 libzink-hisi 已安装
  • [ ] 写 ~/.drirc 白名单(可执行文件名 + dri_driver=zink)
  • [ ] 检查 LD_LIBRARY_PATH 没有指向带旧 Mesa 的目录
  • [ ] 重启游戏,看日志 renderer 是否变成 zink (Maleoon 920)
  • [ ] 关掉 FrameLimiter,先测真实上限,再决定要不要优化
已有 0 条评论 (旧评论在前)
  1. 暂无评论 / 0 Comment
添加新评论 (Markdown Supported)
(ノ°ο°)ノ