雪漫城的风宅

WSL Ubuntu 26.04 下 cc-switch 图形异常与 Mesa D3D12 加速修复记录

· NightingaleWK
技术记录
文章目录

一、问题背景

之前在 Windows 11 + WSL2 Ubuntu 环境中使用 cc-switch 时,曾遇到过 WSLg / Wayland 下界面异常的问题。

当时采用的方案是通过 alias 强制指定:

1
2
SHELL=/bin/sh
GDK_BACKEND=x11

即:

1
alias cc-switch='env SHELL=/bin/sh GDK_BACKEND=x11 /usr/bin/cc-switch'

该方案在当时可以有效规避 cc-switch 的部分 GTK / Wayland 兼容性问题。

但在 Ubuntu 26.04 后续升级后,又出现了新的图形环境异常。

这次问题不再单纯是 Wayland / X11 backend 的兼容性问题,而进一步涉及到了 WSLg 下 Mesa OpenGL 的 GPU 加速路径。

最终定位发现:

当前 Ubuntu 26.04 环境中的 Mesa 默认没有正确选择 WSLg 的 D3D12 Gallium Driver,而是回退到了 llvmpipe CPU 软件渲染。

通过显式指定:

1
GALLIUM_DRIVER=d3d12

可以恢复 NVIDIA GPU 的 D3D12 硬件加速,并使 cc-switch 正常启动。


二、环境信息

本次排查环境:

1
2
3
4
5
6
7
8
Windows 11
WSL2
Ubuntu 26.04
systemd
WSLg
Mesa 26.0.8
NVIDIA Quadro RTX 4000
CC Switch v3.20.2

开发环境本身长期运行于 WSL2 中,因此不希望为了一个 GUI 程序重装 WSL 或修改大量系统配置。

排查原则是:

先确认 WSLg 基础设施,再检查 GPU 加速链路,最后针对应用做最小范围修复。


三、最初现象

在升级 Ubuntu 软件包后,首先注意到 apt upgrade 尾部出现:

1
2
3
Processing triggers for systemd ...
Failed to get properties: Transport endpoint is not connected
Failed to connect to system scope bus via local transport: Connection refused

同时此前 WSL GUI 应用也存在窗口显示异常,因此首先怀疑:

  • systemd 是否异常
  • WSLg 是否正常启动
  • Wayland socket 是否存在
  • GPU 虚拟设备是否正常
  • Mesa 是否可以正常使用硬件加速

因此开始逐层排查。


四、首先检查 systemd 和 WSLg

先完整关闭一次 WSL。

在 Windows PowerShell 中执行:

1
wsl --shutdown

重新打开 Ubuntu 后检查:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
echo "=== PID 1 ==="
ps -p 1 -o pid,comm,args=

echo
echo "=== systemd ==="
systemctl is-system-running 2>&1

echo
echo "=== WSLg ==="
echo "DISPLAY=$DISPLAY"
echo "WAYLAND_DISPLAY=$WAYLAND_DISPLAY"
echo "XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR"

ls -l /dev/dxg
ls -l /mnt/wslg/runtime-dir | head

得到:

1
2
3
4
5
6
=== PID 1 ===
PID COMMAND
1 systemd /sbin/init

=== systemd ===
running

WSLg 环境:

1
2
3
DISPLAY=:0
WAYLAND_DISPLAY=wayland-0
XDG_RUNTIME_DIR=/run/user/1000

同时:

1
/dev/dxg

正常存在。

Wayland socket 也正常:

1
2
/mnt/wslg/runtime-dir/wayland-0
/mnt/wslg/runtime-dir/wayland-0.lock

因此可以确认:

1
2
3
4
5
systemd            正常
WSLg 正常
Wayland socket 正常
DISPLAY 正常
/dev/dxg 正常

这时基本可以排除:

“WSLg 根本没有启动”

这一类基础故障。


五、使用 zenity 验证 WSLg GUI

为了进一步排除应用自身的问题,安装一个简单的 GTK GUI 测试程序:

1
sudo apt install -y zenity

执行:

1
zenity --info --text="WSLg test"

窗口能够正常弹出。

但终端出现:

1
2
3
4
5
6
7
8
libEGL warning: failed to get driver name for fd -1

libEGL warning: MESA-LOADER: failed to retrieve device information

libEGL warning: failed to get driver name for fd -1

MESA: error: ZINK: failed to choose pdev
libEGL warning: egl: failed to create dri2 screen

这一步非常关键。

因为它说明:

WSLg 的窗口系统本身是正常的,但 Mesa 图形渲染链路存在异常。

也就是说问题开始从:

1
WSLg / Wayland

进一步收敛到了:

1
Mesa / OpenGL / GPU acceleration

六、检查 Mesa OpenGL 渲染器

安装 Mesa 测试工具:

1
sudo apt install -y mesa-utils

首先检查默认状态:

1
glxinfo -B

关键输出:

1
2
3
4
5
6
7
Vendor: Mesa
Device: llvmpipe (LLVM 21.1.8, 256 bits)
Version: 26.0.8
Accelerated: no

OpenGL vendor string: Mesa
OpenGL renderer string: llvmpipe (LLVM 21.1.8, 256 bits)

问题至此已经非常明显。

虽然:

1
direct rendering: Yes

但真正决定是否使用 GPU 的关键字段是:

1
Accelerated: no

以及:

1
OpenGL renderer string: llvmpipe

llvmpipe 是 Mesa 的 CPU 软件渲染器。

也就是说当前状态实际上是:

1
2
3
4
5
6
7
Linux GUI
↓
Mesa
↓
llvmpipe
↓
CPU 软件渲染

并没有真正使用 NVIDIA Quadro RTX 4000。


七、强制使用 Mesa D3D12 Gallium Driver

WSLg 的 OpenGL GPU 加速可以通过 Mesa 的 D3D12 Gallium Driver 将 Linux OpenGL 图形调用映射到 Windows Direct3D 12。

因此测试:

1
GALLIUM_DRIVER=d3d12 glxinfo -B

结果立刻发生变化:

1
2
3
4
Vendor: Microsoft Corporation
Device: D3D12 (NVIDIA Quadro RTX 4000)
Version: 26.0.8
Accelerated: yes

OpenGL Renderer:

1
2
OpenGL vendor string: Microsoft Corporation
OpenGL renderer string: D3D12 (NVIDIA Quadro RTX 4000)

同时:

1
Dedicated video memory: 7995 MB

至此可以确认:

Windows GPU → WSL /dev/dxg → D3D12 → Mesa Gallium → OpenGL 的完整硬件加速链路本身是正常的。

真正的问题是:

当前环境下 Mesa 默认没有自动选择 d3d12,而回退到了 llvmpipe。

两种状态对比如下:

状态 Renderer Accelerated
默认 llvmpipe no
GALLIUM_DRIVER=d3d12 D3D12 (NVIDIA Quadro RTX 4000) yes

八、进一步确认 D3D12 相关组件

Mesa D3D12 驱动存在:

1
ls -l /usr/lib/x86_64-linux-gnu/dri/d3d12_dri.so

输出:

1
/usr/lib/x86_64-linux-gnu/dri/d3d12_dri.so

WSL 提供的 DirectX 相关库也正常存在:

1
2
3
4
ls -l \
/usr/lib/wsl/lib/libdxcore.so \
/usr/lib/wsl/lib/libd3d12.so \
/usr/lib/wsl/lib/libd3d12core.so

均正常。

同时:

1
ls -l /dev/dxg

正常存在。

综合这些结果,可以基本排除:

  • Windows NVIDIA 驱动完全不可用
  • WSL vGPU 不存在
  • D3D12 库缺失
  • Mesa D3D12 Driver 缺失

九、再次验证 zenity

使用 D3D12 启动:

1
GALLIUM_DRIVER=d3d12 zenity --info --text="WSLg D3D12 test"

窗口仍然能够正常显示。

虽然仍然存在:

1
2
3
libEGL warning: failed to get driver name for fd -1
libEGL warning: MESA-LOADER: failed to retrieve device information
libEGL warning: failed to get driver name for fd -1

但此前最关键的:

1
2
MESA: error: ZINK: failed to choose pdev
libEGL warning: egl: failed to create dri2 screen

已经消失。

结合 glxinfo -B 中:

1
2
D3D12 (NVIDIA Quadro RTX 4000)
Accelerated: yes

可以认为 D3D12 GPU 加速已经正常建立。

剩余的 EGL warning 暂未影响实际 GUI 使用。


十、测试旧版 cc-switch X11 启动方案

之前为了规避 WSLg Wayland 兼容问题,cc-switch 使用:

1
env GALLIUM_DRIVER=d3d12 SHELL=/bin/sh GDK_BACKEND=x11 cc-switch

应用可以正常打开,但终端出现:

1
2
libEGL warning: DRI3 error: Could not get DRI3 device
libEGL warning: Ensure your X server supports DRI3 to get accelerated rendering

因此当前环境下继续强制:

1
GDK_BACKEND=x11

已经不是最理想的方案。

原来的启动路径大致变成:

1
2
3
4
5
6
7
8
9
cc-switch
↓
GTK
↓
强制 X11
↓
XWayland
↓
DRI3 warning

于是进一步尝试:

保留 D3D12 和 /bin/sh,取消强制 X11,让 GTK 自行使用 WSLg 默认图形 backend。


十一、最终 cc-switch 启动方案

执行:

1
env GALLIUM_DRIVER=d3d12 SHELL=/bin/sh cc-switch

结果:

  • cc-switch 正常启动
  • 主窗口正常显示
  • 列表、字体和 UI 正常
  • 不再出现 X11 下的 DRI3 warning
  • 不再出现 ZINK: failed to choose pdev
  • GPU 可以通过 D3D12 正常工作

程序日志:

1
2
3
=== CC Switch v3.20.2 started ===
正常启动模式:主窗口已显示
Linux: 已对主窗口执行 focus + surface 重激活

此时仍然存在少量:

1
2
libEGL warning: failed to get driver name for fd -1
libEGL warning: MESA-LOADER: failed to retrieve device information

以及:

1
2
3
Gtk-CRITICAL:
gtk_widget_get_scale_factor:
assertion 'GTK_IS_WIDGET (widget)' failed

但均未影响实际启动和使用。

其中 GTK warning 更倾向于应用自身在 Linux / Wayland 环境下的兼容性提示,本次不继续处理。


十二、最终 alias 配置

当然不可能每次启动都手动输入:

1
env GALLIUM_DRIVER=d3d12 SHELL=/bin/sh cc-switch

因此最终仍然采用 alias 做运行时包装。

编辑:

1
nano ~/.bashrc

将原来的:

1
alias cc-switch='env SHELL=/bin/sh GDK_BACKEND=x11 /usr/bin/cc-switch'

修改为:

1
alias cc-switch='env GALLIUM_DRIVER=d3d12 SHELL=/bin/sh /usr/bin/cc-switch'

如果希望再短一点,可以额外增加:

1
alias ccs='env GALLIUM_DRIVER=d3d12 SHELL=/bin/sh /usr/bin/cc-switch'

保存后:

1
source ~/.bashrc

以后正常使用:

1
cc-switch

或者:

1
ccs

即可。


十三、为什么没有全局 export GALLIUM_DRIVER

理论上可以直接:

1
export GALLIUM_DRIVER=d3d12

并写入:

1
~/.bashrc

这样所有 Mesa Gallium 程序都会默认使用 D3D12。

但本次暂时没有这样处理。

原因是:

当前主要需要解决的是 cc-switch,因此优先将环境变量限制在这个程序自己的启动环境中。

这样做的好处是:

  • 不影响其他 Linux GUI 程序
  • 不修改整个 WSL 用户环境的 Mesa Driver 选择逻辑
  • 出现兼容性问题时容易回滚
  • 后续 Ubuntu / Mesa 修复默认行为后,可以直接删除 alias 中的参数

因此当前采用的是:

1
Application Scoped Environment Override

而不是:

1
Global Environment Override

十四、不再强制 GDK_BACKEND=x11

这也是这次处理相较之前方案最大的变化。

旧方案:

1
alias cc-switch='env SHELL=/bin/sh GDK_BACKEND=x11 /usr/bin/cc-switch'

当前方案:

1
alias cc-switch='env GALLIUM_DRIVER=d3d12 SHELL=/bin/sh /usr/bin/cc-switch'

即:

1
2
- GDK_BACKEND=x11
+ GALLIUM_DRIVER=d3d12

实际思路也发生了变化。

之前主要解决:

1
Wayland / GTK 兼容性

现在主要解决:

1
Mesa 默认回退 llvmpipe

而在当前版本的 cc-switch 和 WSLg 环境中,不再强制 X11 后,程序已经能够正常运行。

因此没有必要继续人为指定:

1
GDK_BACKEND=x11

十五、本次完整故障链路

最终整个排查过程可以总结为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
cc-switch GUI 异常
↓
检查 systemd
↓
systemd running
↓
检查 WSLg
↓
DISPLAY / Wayland / /dev/dxg 正常
↓
使用 zenity 测试
↓
GUI 可以显示,但 Mesa / EGL 报错
↓
检查 glxinfo -B
↓
llvmpipe
Accelerated: no
↓
发现 GPU 加速没有启用
↓
GALLIUM_DRIVER=d3d12
↓
D3D12 (NVIDIA Quadro RTX 4000)
Accelerated: yes
↓
测试 cc-switch + GDK_BACKEND=x11
↓
出现 DRI3 warning
↓
取消强制 X11
↓
env GALLIUM_DRIVER=d3d12 SHELL=/bin/sh cc-switch
↓
正常启动
↓
写入 alias

最终状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
WSL2                         ✅
Ubuntu 26.04 ✅
systemd ✅
WSLg ✅
Wayland ✅
/dev/dxg ✅
Mesa ✅
D3D12 Gallium Driver ✅
NVIDIA Quadro RTX 4000 ✅
OpenGL GPU acceleration ✅

默认 llvmpipe ❌
GALLIUM_DRIVER=d3d12 ✅

强制 GDK_BACKEND=x11 不再使用
cc-switch ✅

十六、日后快速检查方法

如果以后再次怀疑 WSLg GPU 加速失效,可以直接:

1
glxinfo -B | grep -E 'Vendor|Device|Accelerated|OpenGL renderer'

如果出现:

1
2
3
Device: llvmpipe
Accelerated: no
OpenGL renderer string: llvmpipe

说明目前仍然在使用 CPU 软件渲染。

测试 D3D12:

1
GALLIUM_DRIVER=d3d12 glxinfo -B | grep -E 'Vendor|Device|Accelerated|OpenGL renderer'

正常应类似:

1
2
3
4
Vendor: Microsoft Corporation
Device: D3D12 (NVIDIA Quadro RTX 4000)
Accelerated: yes
OpenGL renderer string: D3D12 (NVIDIA Quadro RTX 4000)

同时可以确认 WSL GPU 设备:

1
ls -l /dev/dxg

以及 WSLg 环境:

1
2
3
echo "$DISPLAY"
echo "$WAYLAND_DISPLAY"
echo "$XDG_RUNTIME_DIR"

十七、最终方案

最终保留的配置非常简单。

~/.bashrc:

1
2
alias cc-switch='env GALLIUM_DRIVER=d3d12 SHELL=/bin/sh /usr/bin/cc-switch'
alias ccs='env GALLIUM_DRIVER=d3d12 SHELL=/bin/sh /usr/bin/cc-switch'

应用:

1
source ~/.bashrc

以后:

1
ccs

即可启动。

等价于:

1
env GALLIUM_DRIVER=d3d12 SHELL=/bin/sh /usr/bin/cc-switch

十八、结论

这次 cc-switch 在 WSL Ubuntu 26.04 下的 GUI 异常,最终并不是 WSLg 本身损坏。

排查证明:

  • systemd 正常
  • WSLg 正常
  • Wayland 正常
  • /dev/dxg 正常
  • Windows GPU 通道正常
  • Mesa D3D12 Driver 正常
  • NVIDIA Quadro RTX 4000 可以被 D3D12 正确调用

真正的问题在于:

当前环境中 Mesa 默认 OpenGL Renderer 回退到了 llvmpipe,没有自动走 WSLg 的 D3D12 GPU 加速路径。

显式指定:

1
GALLIUM_DRIVER=d3d12

后,OpenGL Renderer 从:

1
2
llvmpipe
Accelerated: no

恢复为:

1
2
D3D12 (NVIDIA Quadro RTX 4000)
Accelerated: yes

同时,相比之前通过:

1
GDK_BACKEND=x11

强制绕到 XWayland 的方案,本次在当前版本环境中直接使用 WSLg 默认 backend 已经可以正常运行,因此最终去掉了 GDK_BACKEND=x11。

最终使用:

1
alias cc-switch='env GALLIUM_DRIVER=d3d12 SHELL=/bin/sh /usr/bin/cc-switch'

作为最小侵入的运行时环境修复方案。

这类问题也再次说明:

WSL GUI “窗口能打开”并不代表 GPU 加速一定正常。

遇到 WSLg 图形异常时,除了检查 DISPLAY、Wayland 和 /dev/dxg,还应该进一步通过:

1
glxinfo -B

确认实际的 OpenGL Renderer。

看到:

1
llvmpipe

和看到:

1
D3D12 (NVIDIA ...)

是两种完全不同的运行状态。

下一篇:膝盖中箭之地 · 大事记