Repository navigation
wsl-gl-host-link 强制 GALLIUM_DRIVER=d3d12,但 xim:mesa 的包内没有 d3d12_dri.so —— WSL2 上 GL 程序报 glx: failed to create drisw screen #382
Description
Activity
- added a commit that references this issue
on Aug 8, 2026 Thanks — this report was accurate and the evidence was exactly what was needed. Both halves are now fixed, in two different places.
Your claim, verified
25.0.7.1 has no d3d12 anywhere. Not just the missing
d3d12_dri.soyou found — it is absent from libgallium'sGALLIUM_DRIVERselector table too (symbols are hidden, so the name table is the right probe):selector table d3d12_dri.solibgallium mesa 25.0.7.1 iris llvmpipe radeonsi softpipe✗ 31 MB mesa 25.0.7.2 d3d12iris llvmpipe radeonsi softpipe✓ 44 MB So forcing
GALLIUM_DRIVER=d3d12on it could only hard-fail. Your root-cause statement was right.What shipped
1. mesa 25.0.7.2 (openxlings/xim-pkgindex#563) — adds
d3d12andiris. That took five prerequisite packages that did not exist or were not wired in (directx-headers,spirv-tools,wayland-protocols, anllvm-devrebuilt with AMDGPU, plus a gcc fix), and a patch for mesa 25.0.7 against glibc 2.44.Verified on the payload:
libgallium → libLLVM.so.20.1(ours, not the host's 18), and none of the build-only libraries reached it.2.
wsl-gl-host-linkno longer forces unconditionally (openxlings/xim-pkgindex#565) — your suggestion (c). It checks<subos>/usr/lib/dri/d3d12_dri.soand, when absent, warns with the remedy and leaves GL on llvmpipe. The check reads the subos view rather than mesa's payload, because that directory is anxvm.filessymlink to the active mesa — so it asks "what will actually be loaded".This matters beyond your case: the sentinel declares a bare
xim:mesa("whatever mesa this home resolves"), so shipping a fixed mesa is not by itself a fix for the sentinel.Your secondary observation was the sharpest one
export GALLIUM_DRIVER=llvmpipe; mcpp run仍然失败You were right, and it invalidated the recipe's own safety argument. The comment said:
A user who exported GALLIUM_DRIVER themselves keeps it (UC-1) … and that escape is why forcing the value here is safe.
subos.envhas exactly two ops —setandprepend(xlings src/core/subos/manifest.cppm:45-46) — and neither is conditional. There was never an escape hatch; it existed only in that comment. Filed as openxlings/xlings#508 for adefault(set-if-unset) op. Until that lands a package cannot offer "the user's value wins", which is why #565 forces less rather than promising an override it cannot deliver.Two of your notes I also corrected
mesa.luaclaimed "twelve driver modules" underlib/dri/. 25.0.7.1 ships 6 entries, 25.0.7.2 ships 8. Removed the number.wsl-gl-host-link.lua's "d3d12_dri.socarries a DT_RPATH ending in the subos lib directory (verified on the shipped payload)". The RPATH half is true — it is a symlink tolibdril_dri.so, whose RPATH ends in<subos>/libon both payloads. The file half was never true of 25.0.7.1, so nothing about it had been verified. Now stated accurately.
Caveat on my side
I have no WSL2 and no Intel GPU here, so
d3d12andirisare in the payload with a clean dependency closure but unexercised. If you can retest on 25.0.7.2 I would like to know whether the GPU path actually initialises — that is the one result this machine cannot produce.- added a commit that references this issue
on Aug 8, 2026 可以验证了,而且不需要 mcpp 新版本
主症状已在包侧解决(openxlings/xim-pkgindex#565)。mcpp 只是把
subos_info.envs里写的东西应用到子进程 —— 配方不再无条件声明那个变量,症状就没有了。当前发布的 mcpp 2026.8.8.2 即可。包侧现在的行为
wsl-gl-host-link改成先看驱动在不在,再决定要不要强制:local dri_d3d12 = path.join(system.subos_sysrootdir(), "usr","lib","dri","d3d12_dri.so") if not os.isfile(dri_d3d12) then -- 不声明 GALLIUM_DRIVER,让 mesa 自己回落到 llvmpipe return true end subos.env{ var = "GALLIUM_DRIVER", op = "set", value = "d3d12", binding = tag }
检查读的是 subos 视图而不是某个已装 payload ——
usr/lib/dri是指向当前生效 mesa 的xvm.files符号链接,所以它问的是「实际会被加载的是什么」。怎么验证
xlings update # 取到 #565 之后的配方 mcpp build && mcpp run
判据(按可信度排序,建议至少看前两条):
-
装机日志。mesa 没带 d3d12 时应出现:
wsl-gl-host-link: this is a WSL host, but the active mesa has no d3d12_dri.so -- NOT forcing GALLIUM_DRIVER=d3d12
—— 有这一行,就说明新配方生效了。 -
变量确实没被设:
mcpp run -- sh -c 'echo "GALLIUM_DRIVER=[$GALLIUM_DRIVER]"'期望是空。若仍打印
d3d12,说明索引还没刷到mcpp cleanhas no middle ground between "keep everything" and "remove target/": fingerprint directories that are no longer current are never collected #565(先xlings update)。 -
程序跑起来:不再是
glx: failed to create drisw screen/ 退出码 255。 -
要 GPU 加速:装 mesa >= 25.0.7.2(带 d3d12 驱动),此时上面第 1 条会变成
GALLIUM_DRIVER=d3d12 (d3d12_dri.so present),且第 2 条会打印d3d12。
你报的「次要观察」:逃生通道 —— 仍未修,且不该由 mcpp 单方面修
export GALLIUM_DRIVER=llvmpipe; mcpp run仍然失败,即 subos 的set覆盖了用户预先导出的值观察属实。我曾在 mcpp 侧把
set改成「用户已 export 就让位」,又撤回了,理由两条:set与「默认值」是两种真实不同的意图。 有些变量 subos 必须说了算 —— 指向它自己 loader 配置的那类,用户 shell 里一个陈旧值就能把环境弄坏。把两者塌成一个,等于从此无法表达前者。- op 词汇表是 xlings 的契约,mcpp 是消费方。 消费方悄悄给一个 op 加第二种含义,会让同一个 subos 因为由谁启动而行为不同。
所以正解是 xlings 新增一个 op(比如
set-if-unset/default:声明默认值,用户可覆盖),配方改用它,mcpp 认它。有一点必须提醒:mcpp 目前会丢弃未知 op,所以那个 op 必须两侧同时到位,xlings 单方面加了等于没加。不过就本 issue 而言,#565 之后逃生通道已经不是必需的了 —— 驱动不在时根本不会去设那个变量。
顺带修掉的一个缺陷(与本 issue 无关,但在同一段代码里)
查这条时发现:
prepend会把调用方的值整个丢掉。解析结果是替换子进程变量的(作为 extraEnv 进去),而prepend只发出声明值 —— 对 PATH 形状的变量,丢掉的是用户的整条搜索路径。已修(#383,已合入 main),会随下一个版本发布。它不影响本 issue 的验证。-
Follow-up on your secondary observation — you were right that it is the application logic, and it is on the mcpp side
这可能属于 mcpp-community/mcpp 的 subos_info 应用逻辑
That guess was correct. I measured xlings' own application and it is conditional in all four backends:
backend code POSIX : "${VAR:=value}"; export VAR;fish if not set -q VAR; set -gx VAR …; endpwsh if (-not $env:VAR) { $env:VAR = … }in-process else if (existing.empty()) { set_env_variable(...) }Verified by injecting a synthetic
op = "set"declaration and entering the subos with the variable already exported:generated: : "${XLINGS_SET_PROBE:=PACKAGE_VALUE}"; export XLINGS_SET_PROBE; $ XLINGS_SET_PROBE=USER_VALUE xlings subos use default --sandbox --cmd 'echo $XLINGS_SET_PROBE' XLINGS_SET_PROBE=USER_VALUEThe user's value wins under
xlings subos use. Undermcpp runit did not, in your measurement — soop = "set"is being applied unconditionally when mcpp readssubos_info.The contract to match:
op = "set"means set if unset — it is a default, not an override. (The name is genuinely misleading; I misread it the same way you did, and I filed and then closed an xlings issue on the strength of that misreading — openxlings/xlings#508.)op = "prepend"composes with an existing value.Fixing that on the mcpp side restores the escape hatch you were looking for, independently of the driver-presence fix that already shipped.
结论:主症状已在包侧修复,关闭。你报的「次要观察」是一条独立的 mcpp 缺陷,已移交 #397(C-7)单独追踪。
主症状
xim-pkgindex#563(mesa 25.0.7.2,带d3d12与iris)+ #565(wsl-gl-host-link改成先看<subos>/usr/lib/dri/d3d12_dri.so在不在,不在就不声明GALLIUM_DRIVER,让 mesa 自己回落 llvmpipe)。你给的三条证据全部成立,根因判断也对。⚠️ 但存量机器不会自动好转 —— 这一条比原先估计的更硬,请照下面处理核验时发现两层原因,任何一层单独成立就够:
config()在你的机器上根本不会再跑。xlings src/core/xim/commands.cppm:748-750的注释是自述:install把已存在的 payload 目录当成「已安装」,连同它的config()hook 一起跳过。而wsl-gl-host-link的版本没变(pkgs/w/wsl-gl-host-link.lua,latest -> 0.1.0;mcpp cleanhas no middle ground between "keep everything" and "remove target/": fingerprint directories that are no longer current are never collected #565 只改了配方体、没有 bump)⇒ 新配方对已装过的机器一行都不执行。- 就算重跑了,旧声明也留着。 新配方在缺驱动时走的是「一条
subos.env都不发」的早退,而 xlings 的记录函数第一行就是installer.cppm:1549的if (declarations.empty()) return true;—— 空批次不触发整节替换。installer.cppm:1626-1630的注释写明这是有意为之:「A package that stops declaring env entirely is NOT handled here … the stale section is removed by uninstall or bysuperseded」。
所以你的
.xlings.json里subos_info.envs["wsl-gl-host-link@0.1.0"]的GALLIUM_DRIVER=d3d12还在。 三条路任选:# (a) 重装该包(会重新执行 config()) xlings uninstall wsl-gl-host-link && xlings install wsl-gl-host-link -y # (b) 直接编辑,删掉那一条声明 $EDITOR ~/.xlings/subos/default/.xlings.json # 找 subos_info.envs → wsl-gl-host-link@0.1.0 # (c) 装 mesa >= 25.0.7.2,让强制变成正当的(此时你会真的走到 d3d12 GPU 路径)
验证用
mcpp run -- sh -c 'echo "[$GALLIUM_DRIVER]"',期望是空 —— 别看装机日志,日志只说明新配方跑过,不说明旧声明已被清掉。你的「次要观察」是这轮里最尖锐的一条,已单独立项
export GALLIUM_DRIVER=llvmpipe; mcpp run仍然失败,即 subos 的set覆盖了用户预先导出的值。这可能属于 mcpp 的 subos_info 应用逻辑。猜得对,而且它至今未修。
src/xlings/subos_info.cppm:256-281取了 ambient 值但对set完全不用:auto amb = ambient_of(d.var); if (d.op == "set") { … out.emplace_back(d.var, value); continue; } // amb 被丢弃
而 xlings 的四个后端全是条件赋值(
xlings/src/core/subos.cppm:1012POSIX: "${VAR:=value}"/:1120fishif not set -q/:1143pwshif (-not $env:VAR)/:1166in-processelse if (existing.empty()))。后果是同一个 subos,xlings subos use进去你的 export 保留,mcpp run进去被覆盖 —— 正是subos_info.cppm:262-272那段注释自己声称要避免的分歧,而分歧是 mcpp 造成的。完整分析、修法与三次反复的历史(
73ab179→1cc1052→c1e9360)见 #397 C-7。感谢这份报告 —— 证据质量很高,它同时暴露了包侧、xlings 侧和 mcpp 侧三处问题。
环境
问题描述
WSL2 上,wsl-gl-host-link 配方(pkgs/w/wsl-gl-host-link.lua)在 subos 里声明 GALLIUM_DRIVER=d3d12,前提是 mesa 包里带有 d3d12 gallium 驱动模块。但实际上包内没有:xim-x-mesa/25.0.7.1/lib/dri/ 只有 kms_swrast_dri.so、swrast_dri.so、zink_dri.so、nouveau_dri.so、radeonsi_dri.so(全是 libdril_dri.so 的符号链接)。Mesa 被强制指定 d3d12 驱动,找不到驱动模块,又不回退到 swrast → GL 上下文创建失败:
glx: failed to create drisw screen
(退出码 255)
复现步骤
mcpp build
mcpp run
→ "glx: failed to create drisw screen",退出码 255
证据
kms_swrast_dri.so -> libdril_dri.so
libdril_dri.so
nouveau_dri.so -> libdril_dri.so
radeonsi_dri.so -> libdril_dri.so
swrast_dri.so -> libdril_dri.so
zink_dri.so -> libdril_dri.so
根因
xim:graphics 栈内的协调缺口:wsl-gl-host-link 依赖 mesa,但 mesa 的配方/包并没有用 -Dgallium-drivers=d3d12 构建 d3d12 驱动。强制 GALLIUM_DRIVER=d3d12 把"驱动缺失"变成硬失败,而不是优雅回退到 llvmpipe。
次要观察
wsl-gl-host-link.lua 里写的逃生通道("用户自己导出 GALLIUM_DRIVER=llvmpipe 会保留")在 mcpp run 应用 subos env 时不生效:export GALLIUM_DRIVER=llvmpipe; mcpp run 仍然失败,即 subos 的 set 覆盖了用户预先导出的值。(这可能属于 mcpp-community/mcpp 的 subos_info 应用逻辑。)
建议修复
相关文件