在 Debian 上用 V100 + A380 跑《原神》,一周踩坑实录

先说结论

折腾了大约一周(11 月 3 日 → 11 月 11 日),我把一台 Dell R730xd 里的 Debian 虚拟机,变成了”V100 负责渲染、A380 负责桌面和视频编码、Moonlight 远程游玩”的游戏机。
游戏能进、画面能出、串流能跑。但是:首次启动黑屏、传送卡在 89%、报错 -1-4308,到现在都没有被我证明已经修好。
所以这不是一篇”教程”,而是一份”我走过哪些弯路、每一步到底证明了什么”的记录。如果你也想在 Linux 上搞类似的东西,希望能帮你少绕几圈。


一、为什么要这么折腾

家里的服务器是一台 Dell PowerEdge R730xd,跑着 Proxmox VE。里面有一张 Tesla V100 32GB,平时用来跑推理和 ComfyUI;还有一张闲着的 Intel Arc A380。

我的想法很朴素:

  • 开一台 Debian 13 虚拟机,装上 KDE Plasma 桌面;
  • 让 V100 去渲染游戏(Wine + DXVK 把 D3D11 翻译成 Vulkan);
  • 让 A380 负责桌面合成和 VA-API 视频编码(它的 HEVC / AV1 编码很能打);
  • 我在 Windows 11 上用 Moonlight 远程玩,3072×1920、60 帧,最好还能开 HDR。

游戏选的是《原神》国服 7.2.0,用 An Anime Game Launcher(AAGL) 管理。

整条链路大概长这样:

flowchart LR
    PC["Windows 11<br/>Moonlight"] <-->|"局域网串流"| HERMES["Hermes<br/>串流服务端"]
    subgraph VM["Debian 13 虚拟机(PVE 直通两张卡)"]
        GAME["Wine + DXVK<br/>YuanShen.exe"] --> V100["Tesla V100<br/>负责渲染"]
        V100 -->|"跨 GPU 呈现"| KWIN["KDE / KWin<br/>Wayland"]
        KWIN --> VD["Hermes-KMS<br/>虚拟显示器"]
        VD --> A380["Arc A380<br/>VA-API 编码"]
        A380 --> HERMES
    end

画出来很优雅,做起来才发现:这条链上至少藏着三个互相独立的故障面。

  1. 游戏本身:Wine / DXVK / Unity 的加载与渲染;
  2. 串流:KWin、虚拟屏、VA-API 编码、Moonlight 的抓帧与传输;
  3. 两张显卡之间:跨 GPU 的显存共享(DMA-BUF)与同步。

后面几乎所有的”坑”,都是因为我一开始没把它们分开看。


二、软硬件清单(方便对照)

项目内容
宿主机Dell R730xd,Proxmox VE 9.2
虚拟机Debian 13.7,40 vCPU,约 30 GB 内存,q35 + OVMF,两张卡 PCI 直通
内核起初 6.12.113,后来升到 backports 的 7.2.12
渲染卡Tesla V100-SXM2-32GB,驱动 580.178.04
桌面 / 编码卡Intel Arc A380,i915 驱动,VA-API
桌面KDE Plasma 6,Wayland,SDDM
启动器AAGL 3.19.8(Flatpak)
Winewine-dwproton-wow64-11.0-11(另装了 spritz-wine-tkg 11.19 做对比)
DXVK3.1.1(另有 2.7)
串流Hermes(Sunshine 系)+ Hermes-KMS 0.4.1 虚拟屏
存储/4t 机械盘;/ISSD 固态盘

三、时间线:一天一个坑

11 月 3 日 ~ 4 日:先让桌面活过来

最开始连”桌面能不能登录”都是问题。

我给 KWin 指定了显卡优先级,让 A380 优先、虚拟 Bochs 显卡兜底,免得桌面合成跑到 V100 上去:

# /etc/environment
KWIN_DRM_DEVICES="/dev/dri/by-path/pci-0000\:01\:00.0-card:/dev/dri/by-path/pci-0000\:00\:01.0-card"

然后 SDDM 开始表演:登录器反复启动又退出,日志里全是

sddm-helper exited with 11
Xorg: Caught signal 4 (Illegal instruction). Server aborting.
QSGRenderThread: segfault ... in libQt6Core.so.6.8.2

我试过 PIXMAN_DISABLE=ssse3 之类的办法,但说实话根因没有定位出来。最后是切到 Wayland 会话 + SDDM 自动登录才算稳定下来。X11 为什么崩,至今是个谜。

顺带一提:V100 早期出现过 Xid 79/154、BAR 异常这类硬件层面的报错,做完 Bus Reset 之后 CUDA 自检、显存读写、PCIe Gen3 x16 都恢复了。这件事我不想假装它没发生过——它是后面所有”稳定性”讨论的背景。

11 月 4 日:游戏下载,以及一个”慢”字

AAGL 装好,选国服,路径放在 /4t/Games/YuanShen。下载器 Sophon 线程从 4 调到 16,速度还是只有 2.5~2.8 MiB/s。我怀疑过 HTTP/2 单连接、Fake-IP、代理规则,但这些都只是怀疑,没有任何一个被正式证实。

11 月 5 日:V100 第一次真正渲染原神

这天有个很重要的里程碑:DXVK 日志里明确出现了 Tesla V100-SXM2-32GB,游戏进了主界面。 也就是说”Linux 上根本跑不起来”这个悲观结论被推翻了,D3D11 → Vulkan 这条底层路径是通的。

但新问题立刻来了:

  • 主界面正常,一按 ESC、开背包、开地图,画面就冻住,声音和背景音乐却还在;
  • 有时候再按 ESC 又能退回去。

这看起来不像”显卡算力不够”,更像是 Wine / DXVK / Unity UI 的兼容问题。

同时我还踩了个低级坑:AAGL 的 config.json 被 root 创建过,导致界面里改 Wine 版本时保存失败(os error 13)。把文件所有者改回普通用户就好了。

教训:别信"我选了什么",要看"实际跑的是什么"

我一度以为自己在测 CachyOS 系的 Wine,结果日志显示实际跑的是 spritz-wine-tkg-staging 11.19-1。每次对比实验,都要去翻真正的启动日志确认 Runner 版本。

11 月 5 日:画面冻住,到底是谁冻住了?

更折磨人的是这个现象:Moonlight 上的画面停在最后一帧,我在服务器上用 KDE 截图,画面却是正常的。 有一次我把游戏进程都杀了,Moonlight 还是停在旧画面。

这说明至少有一部分”冻结”根本不是游戏的问题,而是抓帧 / 编码 / 传输那一段出的毛病。

从这一刻起,我给自己立了一条规矩:遇到”卡住”,先分清三件事——

  1. 服务器本地桌面画面还在不在动?
  2. Moonlight 是不是只是停了旧帧?
  3. Unity 日志里有没有新的资源加载错误?

不先分清,就会在错误的子系统里连续乱改。

11 月 5 日 ~ 6 日:虚拟显示器”四部曲”

我想要一个 3072×1920@60Hz 的虚拟屏。这条路走得最曲折:

方案结果
krfb-virtualmonitor + Portal / PipeWire能出画面,但授权麻烦、容易停帧、断线后虚拟屏会残留
给 A380 灌软件 EDIDDP-1 链路训练失败;HDMI 最高只认到约 2048×1152,目标分辨率被拒
EVDI能工作,但每帧多 4~6 ms 拷贝,帧率只有 39~50 FPS
Hermes-KMS 0.4.1部分场景接近 60 FPS,采集开销降到几十微秒,但引入了新的 DMA 问题(见下文)

最后留下来的是 Hermes-KMS,输出名叫 HERMES-1 / Virtual-2。

另外两个小插曲:

  • KDE 缩放 175% → 100%:全屏时画面抖动、位移的问题明显改善。这是一次有效但局部的修复——后来我把两个虚拟屏都设成 100%,首次启动黑屏照样出现,所以缩放不是黑屏的元凶。
  • A380 的 Render/3D 占用一度到 90%,峰值近 99%,串流只有 30~40 FPS。 把 Moonlight 的请求帧率调低之后明显好转。这提醒我:客户端请求帧率、KWin 合成帧率、Hermes 抓帧帧率、A380 编码负载,是四个不同的数字,不能只盯着其中一个。

11 月 7 日 ~ 8 日:重启后第一次启动必黑屏

这是最玄学的一个问题:每次重启虚拟机后,第一次启动原神会黑屏、菜单卡死;退出再开一次,往往就好了。

排查中 DXVK 日志里反复出现:

err:  Presenter: Failed to query present modes: -13
warn: DXGI: Found monitors not associated with any adapter, using fallback

数量非常夸张:有一次统计是 9,186 次,后来另一次累计超过 26,655 次。

我的拓扑是”V100 渲染、Hermes 虚拟屏输出、A380 编码”,这种跨 GPU 的显示器映射,对 Wine / DXVK 来说确实是高难度场景。但注意:-13 只是证明”查询呈现模式一直在失败”,我没有证据说它就是黑屏的唯一原因。

我还怀疑过 NVIDIA 的 /dev/nvidia-modeset 设备节点是第一次使用时才创建、导致启动慢,于是写了个 nvidia-device-preinit.service 在开机时提前创建。结果:节点是提前有了,-13 照样出现。这个假设没有成立。

11 月 8 日:HDR 的锅到底是谁的?

我想开 HDR10。给 Hermes-KMS 加了模块参数 hdr_enable=1 color_depth=10 之后,串流直接打不开了:

Hermes-KMS output is HDR but the client requested SDR
Capture could not open display [HERMES-1]

一开始大家(包括我自己)都以为是”客户端 HDR 没开”。后来确认:我的 Windows HDR 和 Moonlight HDR 其实都开着。 真正的问题在于我用的那版 Hermes 的”采集就绪检查”里,把动态范围写死成了 SDR——于是服务端永远认为”客户端要的是 SDR”,和 HDR 的虚拟屏对不上,直接 503。

我查到上游后来有相关的修复提交,但没有打到本机上。出于稳妥,我把实验性的 modprobe 参数删掉并重启回退了。所以:HDR 目前没有修好,只是定位到了一个明确的服务端逻辑缺陷。

同一天,内核日志里还抓到了另一件事:

hermes-kms: swiotlb buffer is full (sz: 4194304 bytes), total 32768 (slots), used 0 (slots)

注意那个 used 0:它不等于”缓冲区被占满”,更可能是单次 4MB 的大块映射在 DMA 地址范围里放不下。这属于跨 GPU 图像共享路径的风险,需要专门复现,不能拿它去解释游戏资源读取失败。

11 月 8 日:把游戏从机械盘搬到固态盘

资源加载一直出问题,我自然怀疑 /4t 机械盘太慢。于是把整个游戏复制到 /ISSD:

# 复制(先确认两个挂载点都在、目标空间够,免得写到系统盘)
rsync -aHAXS --numeric-ids --info=progress2,stats2 \
  --human-readable --partial \
  /4t/Games/YuanShen/ /ISSD/Games/YuanShen/
 
# 只校验,不修改
rsync -aHAXS --numeric-ids --checksum --dry-run \
  --itemize-changes \
  /4t/Games/YuanShen/ /ISSD/Games/YuanShen/

总共约 3,684 个文件、168.78 GB(逻辑大小),落盘约 158 GiB。校验结果:零差异。 AAGL 路径和 Steam 快捷方式也都改到了 SSD。

然后——问题照旧。

这其实是个很有价值的负面结果:机械盘慢、文件复制出错,这两条路都被堵死了。 后面也就不必去重新下载 158 GiB。

一个不太体面的操作

在处理 Steam 游戏库权限的时候,我对 /ISSD 执行过 chmod 777。能解决眼前的问题,但这不是一个应该长期保留的权限配置,只是记录在案,提醒自己后面要收紧。


四、最难缠的敌人:89% 卡住和 -1-4308

7.2.0 版本下,加载场景或传送的时候,进度条常常停在 89% 左右,有时能到 100% 却进不去,偶尔弹出这个窗口:

attachments/genshin_error_4308.jpg
现场拍下的报错:发生未知错误,错误码 -1-4308。

加载画面本身也会长时间不动:

attachments/genshin_loading.png
停在加载界面的样子。这张图只能证明”当时卡住了”,说明不了为什么卡。

Unity 日志里最有价值的几行:

HK4EUpload: error asr_003: BlobSignature not match
[AsyncLoad]Archive initiliazing failed when
  BundleLoadState::TryCreateBackingArchive! result=3
Create archive failed, bundle loading failed!
ReadFile failed

(initiliazing 是日志原文的拼写,我没改。)

涉及的是 YuanShen_Data/StreamingAssets/AssetBundles/blocks/00/ 下面的几个 .blk 文件,比如 07803909.blk、07385874.blk、12524766.blk、14414434.blk。读取失败的偏移量每次都不一样。

我能得出的结论是:

已经比较有把握排除的:

  • 两份游戏目录之间的复制误差;
  • 报错的 .blk 文件与官方 pkg_version 清单的 MD5 / 大小不一致(实际是一致的);
  • 明显的 ext4 读错误、磁盘 I/O 致命错误;
  • “机械盘太慢”。

没法排除的:

  • Wine 里 Windows 文件 I/O 的异步 / 内存映射语义和 Unity 实验性 AsyncLoad 的交互;
  • 加载器在并发读取时的竞争条件;
  • 7.1 / 7.2 版本和非官方运行环境本身的兼容性。

文件 MD5 对得上,只能证明磁盘上的字节是对的,不能证明某一次读调用返回的字节、偏移、长度是对的。所以下一步应该去抓运行时的读调用,而不是再下载一遍游戏。

我在 AAGL 的 GitHub 上找到了 Issue 695,里面有人在 7.1 / 7.2 遇到了相似的加载和资源签名问题。这是个很好的旁证,但也只是旁证,不能说我的原因和他们一模一样。


五、为了 NTSync,我给虚拟机换了内核

既然怀疑跟同步原语有关,那就试试 NTSync——这是 Linux 内核里专门为 Wine 做的 Windows NT 同步原语实现,比 ESync / FSync 更贴近 Windows 语义。

问题是:Debian 13 默认的 6.12 内核没有启用 CONFIG_NTSYNC,Stable 的安全更新(6.12.116)也一样没有。好在 trixie-backports 里有 7.2.12。

我的做法是”先模拟、再逐步来、始终留后路”:

  1. apt-get -s 先模拟安装,确认不会卸载别的东西、旧内核镜像还在、根分区空间够;
  2. EVDI 已经不用了,还可能跟新内核冲突,先模拟卸载(只影响这一个包),再真正卸掉;
  3. 先装 headers,让 DKMS 提前编译——NVIDIA 580.178.04、Hermes-KMS 0.4.1、ZFS 2.3.9 全部在新内核上编译通过;
  4. 再装内核镜像本体,检查 initrd、GRUB、ntsync.ko 是否就位;
  5. 旧的 6.12.113 内核和头文件标记为手动安装,防止被自动清理掉;
  6. 加一个带条件的服务,只有内核 ≥ 6.14 才去加载 ntsync,这样将来回退到 6.12 也不会因为找不到模块而报错:
# /etc/systemd/system/ntsync-conditional.service
[Unit]
Description=Load NTSync kernel module on supported Linux kernels
ConditionKernelVersion=>=6.14
 
[Service]
Type=oneshot
ExecStart=/usr/sbin/modprobe ntsync
RemainAfterExit=yes
 
[Install]
WantedBy=multi-user.target

重启后实测:

uname -r        => 7.2.12+deb13-amd64
/dev/ntsync     => crw-rw-rw-(存在)
DKMS            => hermes-kms / nvidia / zfs 均已安装

AAGL 的 Flatpak 沙箱里也能看到 /dev/ntsync。V100、A380、Hermes、ZFS、挂载点都正常。

唯一变红的是之前自己写的 nvidia-device-preinit.service:它在开机早期检查 /dev/nvidia-uvm,那时候节点还没出现,所以报失败;稍后节点就有了,V100 工作正常。这是我自己写的服务的时序问题,不是驱动坏了,也不能说明黑屏已经修好。

11 月 11 日凌晨,AAGL 的同步方式已经从 FSync 切到了 NTSync。

注意这里的措辞

“NTSync 已启用”和”原神不再卡 89%“是两件事。 配置确实切换了、设备也确实存在,但我还没有完成足够多次的冷启动和传送测试,所以现在不能说它修好了问题。


六、顺手踩到的、与原神无关的坑

这些事情和游戏本体无关,但因为发生在同一个环境里,很容易被我自己误当成同一个问题:

attachments/steam_locked.png
Steam 移动《极限竞速:地平线 5》到新库时提示”内容文件已锁定”。这是 Steam 存储库的权限 / 占用问题,不代表原神文件有损坏。

  • Steam / Proton:为了对比,我试过用 Proton 跑《极限竞速:地平线 5》,窗口黑屏、V100 占用 0%,Proton Experimental 11 一样黑屏;试装的 Proton 10.0 也没做完整验证。
  • 输入法:KDE Wayland 下装了 Fcitx5 + Rime,切换快捷键经常被 Moonlight 截走。
  • 手柄:Moonlight 的手柄能在 Linux 里被识别成 Xbox 360 Controller,按键和摇杆都能收到。
  • 剪贴板:打算用 KDE Connect 的剪贴板插件,Wayland 权限会有一些限制。
  • 宿主机:PVE 9.2 的内核和管理器都有可用更新,我只做了 APT 模拟,没有真正升级;另外存储空间偏紧、备份也不充分,需要找一个维护窗口再处理。
  • 更早的背景:9 月份这台机器出现过硬复位(iDRAC 的 PWR2262 / RAC0703),当时和 A380 高负载存在相关性。它是这个项目的风险背景,但我不能凭此断定 11 月的资源读取错误也是它引起的。

七、现在到底解决了什么

项目状态说明
Debian VM 启动✅ 正常Linux 7.2.12,驱动都能编译加载
V100 渲染✅ 已证实DXVK 日志明确选用 V100
A380 桌面 + 编码✅ 已证实KDE 使用 A380,VA-API HEVC / AV1 可用
NTSync 设备✅ 可用/dev/ntsync 存在,Flatpak 内可见
游戏文件迁移✅ 完成rsync 校验无差异,两份各约 158 GiB
全屏抖动🟡 局部修复缩放改 100% 后好转
Hermes 串流🟡 基本可用高负载稳定性待验证
首次启动黑屏❌ 未解决仍有大量 -13 日志
传送 89% / -1-4308❌ 未解决NTSync 效果待验证
HDR10❌ 未解决服务端就绪检查写死 SDR
SWIOTLB / DMA❌ 未解决新内核运行正常 ≠ 高负载已验证
nvidia-device-preinit❌ 待修需要调整服务启动时序

八、这一周教给我的几件事

  1. 把”游戏卡了”拆成三层再说话。 游戏内部资源加载失败、Moonlight 停帧、跨 GPU 显示映射,是三条互不相干的链。“服务器本地画面是否还在动”是最便宜、最有效的分流检查。
  2. 一次只改一个变量。 Runner、同步方式、DXVK 版本、缩放、虚拟屏、HDR 一起动,最后你只会得到一团无法解释的结果。
  3. 别把”已安装 / 已启用”当成”已解决”。 我自己就好几次差点把”配置已切换”写成”问题已修复”。
  4. 日志先于修复。 每次游戏启动 output_log.txt 都会被覆盖,有些关键错误只留在 .last 或者一张手机照片里。现在我每次出问题都会先存一份带时间戳的日志目录,再动手改东西。
  5. MD5 对得上,不代表读得对。 文件校验排除的是”磁盘上的数据”,排除不了”运行时读取行为”。
  6. 别无脑重下 158 GiB,也别随手清 Wine 前缀。 它们会破坏对照实验,还会白白拉长恢复时间。
  7. 别图省事 chmod 777,别用 root 去启动用户态 GUI。 后者直接导致了 os error 13。
  8. 留好后路。 旧内核保留、先备份配置、有 SSH 和 PVE 控制台两条救援通道,再去碰显示栈和内核。

九、接下来准备怎么测

下面是我准备做的受控对比实验(目前都还没做完,别当成已经有结论)。每次只改一个变量,并保存 config.json、Wine 前缀备份和完整日志。

优先级固定什么改变什么看什么
P0内核 7.2.12、同一份游戏、同一 Wine / DXVKNTSync vs FSync反复冷启动 + 传送,对比 -1-4308 与 AsyncLoad 报错
P0同一 Runner、同一显示配置区分”第一次启动”和”第二次启动”-13 次数、黑屏概率、虚拟屏就绪时机
P0/ISSD 原样不动卡在 89% 时保留 Unity + Wine 日志对应 .blk 的读返回值与偏移
P1游戏不运行单独压测 Hermes / KWin / Moonlight 60 FPS排除游戏,确认串流自己会不会冻帧
P1只用 SDRH.264 / HEVC / AV1 逐个对比编码路径与请求帧率的稳定边界
P1先备份 Hermes 配置修复 HDR 就绪检查前后对比HDR10 能否正常进入采集
P2备份 Wine 前缀DWProton vs Spritz 11.19分离 Runner 与同步方式的影响
P2备份 Wine 前缀DXVK 2.7 vs 3.1.1对比 Present 日志与加载表现

记录时我会固定写下:是否第一次启动、场景地点、进度百分比、屏幕模式、HDR / SDR、Runner、Sync、DXVK、内核版本、两张卡的负载、Unity 日志时间戳,以及 Moonlight 是否停在最后一帧。而不是只写一句”又卡了”。


附录:排障时我会优先跑的只读命令

先确认你登录的是 Debian 虚拟机,而不是 PVE 宿主机,再运行下面这些命令。

# 内核 / NTSync / GPU
uname -r
ls -l /dev/ntsync
lsmod | grep -E '^(ntsync|nvidia|nvidia_uvm|i915|hermes_kms|zfs)'
nvidia-smi
lspci -nnk | grep -A4 -E 'VGA compatible|3D controller'
 
# 桌面、服务与内核日志
systemctl is-active sddm
systemctl status ntsync-conditional.service --no-pager
journalctl -b -k --no-pager | grep -Ei 'swiotlb|dma-buf|i915|nvidia|hermes'
 
# 游戏与启动器(只读,不要动凭证)
A="$HOME/.var/app/moe.launcher.an-anime-game-launcher/data/anime-game-launcher"
jq '{wine:.game.wine.selected, sync:.game.wine.sync, path:.game.path.china}' "$A/config.json"
grep -Ei 'BlobSignature|ReadFile failed|Archive initiliazing|AsyncLoad' \
  "$A/prefix/drive_c/users/$USER/AppData/LocalLow/miHoYo/原神/output_log.txt"
 
# 磁盘
findmnt -T /ISSD
df -h /ISSD /4t

几个关键路径

游戏目录     /ISSD/Games/YuanShen          (旧副本保留在 /4t/Games/YuanShen)
AAGL 数据    ~/.var/app/moe.launcher.an-anime-game-launcher/data/anime-game-launcher/
  ├─ config.json              启动器配置
  ├─ runners/                 Wine 运行器
  ├─ dxvks/                   DXVK 版本
  ├─ prefix/                  Wine 前缀(别随便删)
  └─ game.log / debug.log     启动器日志
Unity 日志   prefix/drive_c/users/<用户名>/AppData/LocalLow/miHoYo/原神/output_log.txt
Hermes 配置  ~/.config/hermes/hermes.conf
Hermes 日志  ~/.config/hermes/hermes.log

写于 2026-11-11。这篇记录会随着后续测试更新;如果你也在 Linux 上遇到 BlobSignature not match 或者 -1-4308,欢迎交流你的 Runner、同步方式和内核版本。