话说,我一直想要个好用的远程桌面。高中、大学机房用的远程桌面,无论是联想叠云这样的大牌子还是没听说过的杂牌,体验都十分掉价:系统顺滑不顺滑另说,硬件加速之类的关键功能是根本没有。网上租的便宜 VPS 没有显卡,专业的云桌面服务我又买不起,看来只能自己动手了。

写在开启容器之前

KVM 配置远程桌面比较简单,容器里的就稍微麻烦一点,所以我之前关于远程桌面的尝试都是在 KVM 上进行的。

Intel 比较新的核显有虚拟化功能,IOMMU 则可以将 PCI 设备直通给虚拟机,这样显卡直通的方案应该不需要特殊的驱动,虚拟机里装 Windows 也能用。可惜我的机器既不支持 IOMMU 也不支持显卡虚拟化,只能走 VirGL 方案,装 Windows 是不要想了。

好在 KVM 开启 VirGL 也比较简单,只需要给 qemu 加上 -device virtio-vga-gl(启用相关图形设备)和 -display egl-headless(要求 qemu 用 EGL 离屏渲染。EGL 是一种 API )就好。别忘了给宿主机安装显卡驱动,还有打开 qemu 内建的远程桌面(我用的是 spice )。

如果想用 libvirt 管理 KVM,目前需要手写 XML,添加一段自定义的图形设备,比如这样:

<graphics type='egl-headless'>
<gl rendernode='/dev/dri/renderD128'/>
</graphics>

VirGL 的兼容性似乎不太好,我试着启动了几张不同的镜像,openSUSE Leap 15.4 上 KDE 和 LXQt 显示正常,Xfce4 就是黑屏,另外画面撕裂的问题也没解决好,同时 VirGL 下 3D 性能大约会打个对折,遂放弃 KVM。

话说最近 VirtualBox 新增了为虚拟显卡启用 DirectX 的功能,这个需要宿主机支持 Vulkan。我的老台式机当然不支持 Vulkan,不过在新笔记本上说不定可以试试。

Xvnc+VirtualGL

虚拟机玩不起来,那就玩容器吧。

Xvnc 说起来很简单,就是个支持 VNC 连接的显示服务器嘛,很多人都用过。出于某种原因(我也不知道是什么),tigervnc 并不支持硬件加速的 3D 渲染,想在这上面给 3D 程序加速就得用 VirtualGL 之类的工具……

VirtualGL 功能就比较多,据说用双显卡笔记本的同学会用它在独显上运行游戏,不过我打算只用一下它通过 EGL 后端提供 GLX 界面的功能:VirtualGL 的文档说明,它会截取 3D 程序关于 GLX 的系统调用,自己提供一个支持硬件加速的 GLX 界面,这样就算 X 服务器本身不支持加速也没关系。

安装 VirtualGL,运行一下 vglserver_config,选择使用 EGL 后端。运行 3D 程序的时候,在程序命令前加上 vglrun -d 显卡路径 就可以了。别忘了把主机上的 /dev/dri 通进容器里。

这样一来 GLX 程序基本都能加速成功,我这里 Minetest、Blender 之类的程序都能正常启动,SuperTuxKart 会黑屏。

With VirtualGL

Without VirtualGL

有无 VirtualGL 的对比,性能悬殊。

倒是没能成功让 EGL 程序吃上加速,Firefox、Chromium 都是软件渲染,体验一般。如果有同学知道怎么给 VirtualGL 开 EGL 程序的硬件加速,或者让 EGL 程序直接访问 DRI……请给我写封电子邮件吧。

wlroots+wayvnc

Xvnc 下还有什么加速的方法我不知道,不过现在 Wayland 完成度越来越高,不如先试下转战 Wayland 阵营。KDE 这边的 KWin 据说已经支持远程桌面了,但我打开 Krfb,用别的主机怎么也连不上。GNOME 下的 Mutter 我也不会用,只能试下我并不熟悉的 wlroots 系 Wayland Compositor。

wayfire 和 sway 都是相对有名的 wlroots 系 Wayland Compositor。Debian Sid 有打包 wayfire,不过这两天貌似坏了……我换了个 ArchLinux Docker容器,Arch 官方源没打包 wayfire(依云姐姐说,ArchCN 源打包了。想用 wayfire 的同学可以去 ArchCN 源看看)。记得把宿主机上的设备挂载进去,在 docker run 的参数里增加一项 --device /dev/dri:/dev/dri

安装 wayvnc、sway、mesa-utils、xorg-xwayland:pacman -S wayvnc sway mesa-utils xorg-xwayland。我还装了 tmux,用着方便。

先切换到普通用户,再启动 sway:

# 设置运行时目录。如果不存在的话手动创建一下。1000是我的 UID,如果和你的不一样,就相应地调整一下
export XDG_RUNTIME_DIR=/run/user/1000

# 要求 wlroots 使用 headless 后端
export WLR_BACKENDS=headless

sway

启动 wayvnc:

export XDG_RUNTIME_DIR=/run/user/1000

# 设置 Wayland 显示号
export WAYLAND_DISPLAY=wayland-1

# 让 wayvnc 监听所有来源的连接,5900 是端口号。如果不想让局域网的别人连接,就给 IP 设为 127.0.0.1
wayvnc 0.0.0.0 5900

先看下硬件加速能不能用:

export XDG_RUNTIME_DIR=/run/user/1000

#用 XWayland 运行程序的话,还需要设置 X 下的显示号
export DISPLAY=:0

export WAYLAND_DISPLAY=wayland-1

glxinfo

eglinfo

glxinfo、eglinfo 显示:

...
Vendor: AMD (0x1002)
Device: RENOIR (renoir, LLVM 14.0.6, DRM 3.42, 5.14.21-150400.24.21-default) (0x1636)
...

...
Wayland platform:
EGL API version: 1.5
EGL vendor string: Mesa Project
EGL version string: 1.5
EGL client APIs: OpenGL OpenGL_ES
EGL driver name: radeonsi
...

...
X11 platform:
EGL API version: 1.5
EGL vendor string: Mesa Project
EGL version string: 1.5
EGL client APIs: OpenGL OpenGL_ES
EGL driver name: radeonsi
...

看样子没大问题。

用 VNC 连接器连上容器。启动 3D 程序,比如我这边是 SuperTuxKart:

export XDG_RUNTIME_DIR=/run/user/1000

# 我们用 XWayland 运行 SuperTuxKart,所以设置的是 X 下的显示号
export DISPLAY=:0

supertuxkart

SuperTuxKart

轻松自如,如鱼得水。

Chromium、Minetest 啥的也能正常加速,不过没有鼠标锁定,玩 Minetest 当然会比较难受:

Chromium

Chromium 不关沙盒没能启动成功,不知道和 Docker 容器有没有关系。

Minetest

这样的桌面不会独占什么设备,所以后台挂多少个容器理论上都没问题。LXC 或者其它容器平台,或者手搓的容器应该也能正常使用,不过我还没试过。

方案的不完美

标准的 VNC 传不了声音,更没有什么鼠标锁定、USB 重定向的高级功能,用起来当然连 SPICE 都比不上,现在来看运行个制图软件比较合适(耶鲁大学也有关于 VirtualGL 的文档,文档上他们搞这个貌似就是拿来运行 MatLab 的),3D 游戏体验不会很合格。

另外 VNC 在网络不好的条件下表现很差,不巧我们学校的校园网就是很不稳定的类型,连接延迟巨大或者频繁断开恐怕在所难免了。

关于云服务

远程桌面,如果由商业公司提供的话,也可以算是云服务了。我上小学的时候,特别喜欢、并且十分信任云服务,几乎什么东西都要往网盘存一份,能白嫖到云桌面也高兴得不行。

现在我感觉,那时候的我特别傻。只有自己手里的,才是信得过的。

在学校放台 NAS,运行个这样的桌面,不知道这样算不算是有了能信得过的远程桌面。