From 173a18b842464a774fb6b748220c9bca7d7d84a9 Mon Sep 17 00:00:00 2001 From: AskaEth Date: Sat, 7 Nov 2026 08:28:36 +0800 Subject: [PATCH] =?UTF-8?q?feat(termux):=20glibc=20=E6=9E=84=E5=BB=BA?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=90=AF=E7=94=A8=E8=87=AA=E7=BC=96=20Mesa?= =?UTF-8?q?=2026=20turnip=20ICD=EF=BC=88GPU=20=E6=89=93=E9=80=9A=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - app/boot/termux_gpu:glibc 构建 + Termux 且随附 ICD 存在时,在探测前设 VK_ICD_FILENAMES/VK_DRIVER_FILES;用户显式设置不覆盖 - 文档:Mesa 26.2.6 + KGSL 的完整构建/安装/验证步骤(含 shebang、 --wrap-mode=nofallback、C++/链接参数三处坑) - 实测:wgpu 选中 Adreno 840(turnip Mesa 26.2.6),截图首帧 61 ms - README.termux:GPU 标 ✅,MC 标 🟡(glibc JRE+AWT 已验证,GLX 待 GL 构建) --- README.termux.md | 16 ++--- crates/app-iced/src/app/boot.rs | 3 + crates/app-iced/src/app/boot/termux_gpu.rs | 58 +++++++++++++++++ packaging/docs/termux-glibc-build.md | 73 +++++++++++++++------- 4 files changed, 118 insertions(+), 32 deletions(-) create mode 100644 crates/app-iced/src/app/boot/termux_gpu.rs diff --git a/README.termux.md b/README.termux.md index 1a58b7b..e893fcf 100644 --- a/README.termux.md +++ b/README.termux.md @@ -14,8 +14,8 @@ | 横屏适配 | ✅ | 默认窗口按 X 屏幕等比自适应(`source=termux-screen`) | | Java 发现 | ✅ | `JAVA_HOME`/PATH + `$PREFIX/lib/jvm` 扫描 | | Java 自动安装 | ✅ | `ull java install 17` 由内置镜像装完 openjdk-17(约 20 s) | -| GPU(wgpu) | ⛔ | glibc 侧 Mesa 24.2.6 不支持 Adreno 840;Arch 26.2.6 缺 KGSL。CPU 渲染可用 | -| Minecraft 运行 | ⏳ | 无官方 Android natives;计划走 glibc JVM(见下) | +| GPU(wgpu) | ✅ | 自编 Mesa 26.2.6 + KGSL;wgpu 选中 Adreno 840(Vulkan/turnip) | +| Minecraft 运行 | 🟡 | glibc JRE(Temurin 21.0.13)可跑,AWT/X11 正常;GLX 待 Mesa 26 GL 构建 | ## 快速开始 @@ -34,17 +34,17 @@ DISPLAY=:0 ./unlucky-launcher-iced --software-renderer ## 已知边界 - 仅单机(OnePlus 15 / Android 17)验证,试验级、不在发布矩阵内。 -- **GPU**:bionic 侧 zink/turnip 可用;glibc 侧被驱动挡住——Termux 的 glibc Mesa 24.2.6 - 不认识 Adreno 840,Arch 的 26.2.6 是 Linux/DRM 构建、缺 KGSL。需要 Mesa 26+ 的 - glibc+KGSL 构建;在那之前用 CPU(tiny-skia)。GPU 变体会自动降级,不会崩。 +- **GPU**:已打通,但驱动是自编的(Mesa 26.2.6 + KGSL),装到 + `$PREFIX/glibc/{lib,share/vulkan/icd.d}` 后应用会自动启用;Termux 官方源里的 + glibc Mesa 太旧(24.2.6 不认识 Adreno 840)。驱动缺失时自动降级 CPU,不会崩。 - **MC**:Android 原生 natives 走不通(LWJGL 没有官方 Android/bionic 产物,且 GLFW 的 窗口模型与 termux-x11 的 X11 不兼容)。可行路线是 glibc JVM(Temurin linux-aarch64 + - glibc Mesa),让 MC 的 Linux natives 在 glibc 进程里正常加载。 + glibc Mesa)——JRE 与 AWT/X11 已验证,GLX 还差一份 Mesa 26 的 GL 构建。 - Termux 上三条测试失败是环境差异(`/proc/*/children`、长路径脱敏、mtime flaky), PC 的 Linux CI 不受影响。 ## 后续 -1. Mesa 26+ 的 glibc/KGSL 构建(解锁 GPU) -2. MC 运行链:glibc JVM(Temurin linux-aarch64 + glibc Mesa);proot 作为备选 +1. Mesa 26 GLX(zink/softpipe)构建 → MC 的 LWJGL/GLFW 打通 +2. MC 运行链接线:启动器在 Termux 上改用 glibc JVM(Temurin),bionic java 留给 UI/CLI 3. 剪贴板/IME 在 termux-x11 下的行为验证 diff --git a/crates/app-iced/src/app/boot.rs b/crates/app-iced/src/app/boot.rs index bc93fae..38161ed 100644 --- a/crates/app-iced/src/app/boot.rs +++ b/crates/app-iced/src/app/boot.rs @@ -30,6 +30,7 @@ use super::{MIN_SIZE, WINDOW_SIZE}; mod diagnostics; mod fallback; +mod termux_gpu; mod termux_window; use fallback::{on_failure, respawn, OnFailure}; @@ -40,6 +41,8 @@ pub(crate) fn run(options: Options) -> iced::Result { let boot_started = Instant::now(); // ① 探测(判据取在哪、日志在 `report_boot` 里统一打) + // Termux + glibc 构建:装了我们自编的 turnip ICD 就先生效,auto 也能选到 GPU。 + termux_gpu::enable(); let boot = boot_probe(&options); let decision = boot.decision; diagnostics::report_boot(&options, &boot.probe, &decision); diff --git a/crates/app-iced/src/app/boot/termux_gpu.rs b/crates/app-iced/src/app/boot/termux_gpu.rs new file mode 100644 index 0000000..ee14b8f --- /dev/null +++ b/crates/app-iced/src/app/boot/termux_gpu.rs @@ -0,0 +1,58 @@ +//! Termux 上自动启用随附的 Vulkan ICD(glibc 侧 turnip,`ull_freedreno.json`)。 +//! +//! 背景:Termux 软件源里的 glibc Mesa(24.2.6)不认识 Adreno 840,硬件 GPU 需要用 +//! `packaging/docs/termux-glibc-build.md` §5 里自编的 Mesa 26(KGSL)。驱动装在 +//! `$PREFIX/glibc/share/vulkan/icd.d/ull_freedreno.json` 时,这里在探测之前把它设进 +//! `VK_ICD_FILENAMES` / `VK_DRIVER_FILES`,让 `auto` 也能选到 GPU。 +//! +//! 只在 **glibc 构建**(`target_os = "linux"`)上生效:Termux 原生(bionic)构建的 +//! `target_os = "android"`,glibc 驱动对它没有意义。用户显式设了这两个变量时不覆盖。 + +use std::path::{Path, PathBuf}; + +use unlucky_core::platform::paths::ProcessEnv; +use unlucky_core::platform::termux; + +/// 随附 ICD 的相对路径(相对 `$PREFIX`)。 +const ICD_REL: &str = "glibc/share/vulkan/icd.d/ull_freedreno.json"; + +/// 在 GPU 探测之前调用:装了就启用,没装就什么都不做。 +pub(super) fn enable() { + if !cfg!(target_os = "linux") { + return; + } + if std::env::var_os("VK_ICD_FILENAMES").is_some() + || std::env::var_os("VK_DRIVER_FILES").is_some() + { + return; + } + let Some(prefix) = termux::prefix(&ProcessEnv) else { + return; + }; + let icd = icd_path(&prefix); + if icd.is_file() { + std::env::set_var("VK_ICD_FILENAMES", &icd); + std::env::set_var("VK_DRIVER_FILES", &icd); + } +} + +/// `$PREFIX` 下随附 ICD 的路径(纯函数,测试用)。 +fn icd_path(prefix: &Path) -> PathBuf { + prefix.join(ICD_REL) +} + +#[cfg(test)] +mod tests { + use super::icd_path; + + #[test] + fn icd_path_is_under_the_glibc_prefix() { + let path = icd_path(std::path::Path::new("/data/data/com.termux/files/usr")); + assert_eq!( + path, + std::path::PathBuf::from( + "/data/data/com.termux/files/usr/glibc/share/vulkan/icd.d/ull_freedreno.json" + ) + ); + } +} diff --git a/packaging/docs/termux-glibc-build.md b/packaging/docs/termux-glibc-build.md index fe8c84f..ae5df07 100644 --- a/packaging/docs/termux-glibc-build.md +++ b/packaging/docs/termux-glibc-build.md @@ -169,37 +169,62 @@ DISPLAY=:0 .gnu/target/release/unlucky-launcher-iced \ - 已实测:`ull java install 17` 从 SAU 镜像装完 `openjdk-17`(含 `openjdk-17-x`), 约 20 秒;`ull java list` 随后列出 `[system]` 的 17。 -## 5. GPU(已排查,当前被驱动挡在 glibc 侧) +## 5. GPU(已打通:自编 Mesa 26.2.6 + KGSL) -termux-x11 的 X 客户端**可以**走硬件:本机 bionic 栈实测 -`glxinfo -B` → `zink Vulkan 1.4 (Adreno 840 (MESA_TURNIP))`、`Accelerated: yes`, -`vulkaninfo` 中 Adreno 设备带 `VK_KHR_xcb_surface` / `VK_KHR_xlib_surface`。 +termux-x11 的 X 客户端可以走硬件;glibc 侧的问题在**驱动**,不在 loader: -glibc 侧已把链路搭好并实测到具体阻塞点: +1. `vulkan-icd-loader-glibc` + ICD JSON 本身正常。 +2. Termux 软件源的 glibc Mesa 24.2.6 不认识 Adreno 840 + (`chip_id = 44050A31 is unsupported`)。 +3. Arch 的 `vulkan-freedreno 26.2.6` 能加载,但它是 Linux/DRM 构建,缺 KGSL + (`/dev/dri` 对 `untrusted_app` 被 SELinux 拒绝)。 -1. **loader 正常**:`vulkan-icd-loader-glibc` + 自写 ICD JSON 能加载 ICD。 -2. **Termux 的 glibc Mesa 太旧**:`mesa-vulkan-icd-freedreno-glibc` 是 24.2.6(2024), - `vulkaninfo` 报 `chip_id = 44050A31, gpu_id = 6860 is unsupported` - (Adreno 840 不在该版本的支持表里)。 -3. **Arch 的新驱动也走不通**:`vulkan-freedreno 26.2.6`(Arch Linux ARM)能加载、 - 但它是 Linux/DRM 构建,找不到设备——Android 的 GPU 走 KGSL,而 - `/dev/dri` 对 `untrusted_app` 被 SELinux 拒绝(`ls /dev/dri` → Permission denied, - 设备节点本身是 `crw-rw-rw-`)。 - -结论:glibc 侧要用硬件 GPU,需要一个 **Mesa 26+ 的 glibc 构建且带 Android/KGSL 后端**; -现有包都缺一半。在那之前用 CPU(tiny-skia)。 - -GPU 变体仍可构建并验证降级链: +**解法:给 glibc 自编一份带 KGSL 的 Mesa 26.2.6。** 本机实测通过: ```sh -cargo ... build --release -p unlucky-app-iced # 默认 feature,带 wgpu -VK_ICD_FILENAMES="$PREFIX/glibc/share/vulkan/icd.d/freedreno_icd.aarch64.json" \ -VK_DRIVER_FILES="$VK_ICD_FILENAMES" \ - DISPLAY=:0 .gnu/target/release/unlucky-launcher-iced --renderer=gpu +# 1) 源码 + 依赖 +# mesa-26.2.6.tar.xz(archive.mesa3d.org) +# Debian libstdc++-14-dev 的头($G/gnu-support/usr/include/c++/14) +# meson / ninja(pip 装 meson) +# 2) 把源码里 *.py 的 shebang 从 #!/usr/bin/env python3 改成 Termux python3 +# (Android 没有 /usr/bin/env) +# 3) meson setup(cc-glibc 包装器:-c 不带链接参数、C++ 加 -stdlib=libstdc++、 +# 共享库链接加 -lstdc++;详见 §3) +meson setup build3 --native-file="$G/mesa-native.ini" --wrap-mode=nofallback \ + -Dbuildtype=release -Dstrip=true -Dplatforms=x11 \ + -Dvulkan-drivers=freedreno -Dfreedreno-kmds=kgsl \ + -Dgallium-drivers=zink,softpipe -Dglx=dri -Dopengl=true -Degl=enabled \ + -Dgles1=disabled -Dgles2=enabled -Dllvm=disabled -Dgbm=disabled \ + -Dvideo-codecs= -Dzstd=enabled -Dbuild-tests=false +ninja -C build3 ``` -没有可用驱动时它会打印具名错误并**自动降级**到 tiny-skia(同一进程不能重建事件循环, -降级走 respawn),所以 GPU 变体在只有 CPU 的环境里也能跑。 +`--wrap-mode=nofallback` 是为了跳过 libarchive 子项目(它只被 freedreno 的 decode 工具需要, +且它自带的 `id_t` 兜底宏会和 glibc 头冲突)。 + +安装与启用: + +```sh +cp build3/src/freedreno/vulkan/libvulkan_freedreno.so \ + "$PREFIX/glibc/lib/libvulkan_freedreno_ull.so" +cat > "$PREFIX/glibc/share/vulkan/icd.d/ull_freedreno.json" < ICED_BACKEND=wgpu +[gpu] Selected: AdapterInfo { name: "Adreno (TM) 840", driver: "turnip Mesa driver", + driver_info: "Mesa 26.2.6", backend: Vulkan } +[shot] 1657x1067 renderer=wgpu,首帧 61 ms +``` + +没装驱动/没有 GPU 时仍会打印具名错误并自动降级 tiny-skia(同一进程不能重建事件循环, +降级走 respawn),所以 GPU 变体在纯 CPU 环境也能跑。 ## 6. 已知边界