dantiicu/wine-nx

GitHub: dantiicu/wine-nx

该项目是一个实验性的 Nintendo Switch Wine 运行时,通过集成 Horizon/libnx 系统服务在 Switch 上加载和运行 AArch64 Windows PE 程序。

Stars: 57 | Forks: 1

# Wine-NX 开关 Wine-NX 是一个专注于 Nintendo Switch 的 Wine 启动项目。其目标是利用 libnx/Horizon 服务来处理进程、内存、输入、文件、显示,并最终实现 GPU 呈现,从而在 Switch NRO 中运行 AArch64 Windows PE 程序。 这个代码库不再仅仅是一个基础的 Horizon 探测程序。它是 Switch Wine 运行时、进程内 Horizon/Wine server 工作、win32u Switch 显示驱动程序以及用于硬件测试的 SD 卡打包程序的工作树。 ## 当前状态 截至最新的运行时工作,该项目可以构建并暂存一个 Switch NRO 运行时,用于启动以下来源的 Wine PE 目标: ``` sdmc:/switch/wine ``` 记事本是目前主要的真实 GUI 测试目标。它的启动程度已经足以显示主窗口、边框、菜单栏、菜单弹出窗口、文本渲染以及触摸驱动的菜单交互。它仍处于实验阶段,尚不能用于生产环境:响应速度较差,呈现过程极其依赖软件计算,且部分真实应用的子系统仍不完善。 ## 目前可行的功能 ### Switch 构建与打包 - `wine-nx-probe/build-switch.sh` 使用 `devkitpro/devkita64` Docker 镜像构建 Switch 运行时。 - 该脚本将在以下路径暂存一个可运行的 SD 卡包: ``` wine-nx-probe/build-switch/sd-card/switch/wine ``` - 运行时 NRO 输出: ``` wine-nx-probe/build-switch/wine-nx-runtime.nro wine-nx-probe/build-switch/sd-card/switch/wine/wine-nx-runtime.nro ``` - `WINE_NX_APP` 选择暂存的目标: ``` WINE_NX_APP=gui ./wine-nx-probe/build-switch.sh WINE_NX_APP=notepad ./wine-nx-probe/build-switch.sh ``` - 该包现在会将 Wine NLS 文件和 Wine 字体暂存到 Switch 包中,包括等效于 `C:\windows\fonts` 和 `share/wine/fonts` 的目录。 ### 运行时加载器 - 运行时可以从暂存的包中引导 Wine ARM64 PE 目标。 - 冒烟测试应用和记事本路径已具备 PE 导入解析、加载器交接、Wine DLL 暂存以及运行时目标选择功能。 - 运行时在 NRO 中携带了一个构建标记,以便硬件日志能够确认实际运行的是哪个二进制文件。 - 日志输出至: ``` sdmc:/switch/wine/wine-nx-runtime.log sdmc:/switch/wine/horizon-trace.log ``` ### Horizon 和 Wine Server 底层支持 - 早期的 Horizon 基础元件已得到验证:TLS 模型、可执行内存/JIT 别名处理、线程设置、地址空间预留以及 Switch 安全的运行时日志记录。 - 进程内 Horizon/Wine server 路径已足够活跃,可以服务于当前的 NTDLL 和 USER/GDI 流程。 - Win32 syscall 调度可用于已执行的 `win32u` 调用。 - USER server 工作的覆盖率已满足 GUI 路径需求: - atoms; - window station 和 desktop 基础; - 类的创建/注册; - 顶级和弹出窗口对象; - 足以满足当前窗口需求的共享会话样式定位器/数据。 ### GDI 和 USER 启动 - GDI 软件渲染正通过 Wine 的 DIB 路径运行。 - GUI 冒烟测试应用验证了 DC 创建、兼容 DC、DIB section、bitmap、StretchDIBits 风格的光栅操作、对象删除以及光标/菜单绘制。 - `RegisterClassW` 和 `CreateWindow` 已跨越最初的 server 对象阻碍。 - 基本的记事本非客户区渲染正常工作: - 主边框; - 标题/操作按钮; - 菜单栏; - 菜单弹出表面; - 通过 FreeType 支持的 Wine 字体渲染的文本。 ### Switch 显示驱动 - `dlls/win32u/winnx_drv.c` 是特定于 Switch 的 win32u 显示驱动程序。 - 它向 Wine 报告有一个 1280x720 的主显示器。 - Wine 窗口表面渲染到普通的软件 DIB 内存中,然后驱动程序将脏像素 blit 到 libnx framebuffer。 - 添加了弹出窗口/菜单表面恢复功能,以便在弹出窗口隐藏或移动时可以再次覆盖旧的菜单像素。 - 脏区域呈现工作避免了部分全表面刷新。 - 批量呈现工作保持一个待处理的 framebuffer 处于开启状态,并在更高层次的边界进行呈现,而不是将每个微小的脏矩形都加入队列。 ### 输入 - Switch 触摸屏输入通过 libnx 进行采样。 - 触摸被转换为绝对的 Win32 鼠标输入。 - 非客户区命中测试工作良好,足以与记事本边框和顶部菜单进行交互。 - 添加了 `get_window_children_from_point` 支持,以实现正确的子窗口命中路由。 ### 真实 GUI 里程碑 当前的真实应用里程碑是 Wine 记事本: - 窗口在 Switch 上显示; - 边框/控制图标渲染正确; - 菜单字体正常渲染; - 通过触摸可以部分进行顶部菜单交互; - 可以绘制并消除弹出窗口; - 应用程序明显处于活动状态,但速度较慢,尚不能提供舒适的 UI 体验。 ## 当前问题 ### 呈现速度依然过慢 CPU 仍有余量,这充分表明瓶颈在于呈现和同步,而不是原始的 CPU 光栅化。 当前的 libnx Framebuffer 路径使用 `framebufferMakeLinear()`。这使得驱动程序易于编写,但每次调用 `framebufferEnd()` 时,都会将完整的 1280x720 阴影缓冲区转换为 block-linear 布局,然后再将其加入 Switch compositor 的队列。即使 Wine 仅更改了一个小的菜单高亮显示,呈现路径的开销依然可能很高。 目前的批量补丁减少了这种情况发生的频率,但真正的性能提升在于 GPU 呈现路径。由于此代码树已经具有可用的 Mesa/NVK Vulkan 移植,因此首选方向是 Vulkan/NVK compositor:将 Wine DIB/窗口表面上传到 GPU 纹理中,进行合成,并每帧呈现一次。 ### UI 完整性仍处于早期阶段 已知的待完善领域: - 菜单功能正常,但尚未完全达到完美的 Windows 效果; - 弹出窗口/菜单的 z-order 和失效处理仍需更多的 compositor 逻辑; - 触摸输入需要更好的捕获、焦点、拖拽和双击行为; - 尚无手柄/键盘文本输入路径; - 尚无真正的 GPU 加速; - 记事本作为一个里程碑是有效的,但这并不能证明任意的 GUI 应用程序都已准备就绪。 ### Wine 子系统差距 真实的应用程序需要在以下方面做更多工作: - USER 消息队列和窗口状态的边缘情况; - 通用控件和对话框; - shell/comdlg/shell32 行为; - 许多应用程序使用的 COM/OLE 路径; - 注册表和 prefix 行为; - 超出暂存的 Wine 字体集的字体发现/回退; - 剪贴板、IME、键盘和手柄输入; - 音频、网络和多进程行为作为后续里程碑。 ## 构建 ### 宿主机系统设置 Switch NRO 构建在使用 `devkitpro/devkita64` 镜像的 Docker 内运行。 如有需要,该脚本会在该容器内安装缺失的 Switch portlibs,包括用于字体渲染的 FreeType/Harfbuzz。 宿主机端的 Wine PE 重建路径使用 LLVM-MinGW。默认的预期路径会被 git 忽略: ``` wine-nx-probe/toolchains/llvm-mingw-20260505-ucrt-macos-universal ``` 如果 `wine-nx-probe/toolchains/` 缺失,请从指定的 LLVM-MinGW 发行版恢复它: ``` mkdir -p wine-nx-probe/toolchains curl -L -o wine-nx-probe/toolchains/llvm-mingw-20260505-ucrt-macos-universal.tar.xz \ https://github.com/mstorsjo/llvm-mingw/releases/download/20260505/llvm-mingw-20260505-ucrt-macos-universal.tar.xz tar -C wine-nx-probe/toolchains \ -xf wine-nx-probe/toolchains/llvm-mingw-20260505-ucrt-macos-universal.tar.xz ``` 对于其他宿主机/工具链布局,请将构建指向提取后的 LLVM-MinGW 目录: ``` LLVM_MINGW_DIR=/path/to/llvm-mingw WINE_NX_APP=notepad ./wine-nx-probe/build-switch.sh ``` ARM64 PE Wine 构建树也会被 git 忽略: ``` wine-nx-probe/build-wine-arm64-pe-clean wine-nx-probe/build-wine-arm64-pe-local ``` 这些目录是用于重建记事本和 Wine PE DLL 的一次性 Wine PE 构建树。`wine-nx-probe/build-wine-arm64-pe-clean` 是默认的 PE 构建目录。当 `WINE_NX_APP=notepad` 且 `wine-nx-probe/build-wine-arm64-pe-local` 存在时,`build-switch.sh` 会优先使用本地树作为暂存程序。使用以下命令覆盖任一路径: ``` WINE_NX_PROGRAM_BUILD_DIR=/path/to/wine-pe-build WINE_NX_APP=notepad ./wine-nx-probe/build-switch.sh ``` 从代码库根目录重新创建 PE 构建树: ``` PE_BUILD_DIR=wine-nx-probe/build-wine-arm64-pe-clean mkdir -p "$PE_BUILD_DIR" ( cd "$PE_BUILD_DIR" PATH="$PWD/../toolchains/llvm-mingw-20260505-ucrt-macos-universal/bin:$PATH" \ ../../configure \ --enable-archs=aarch64 \ --disable-tests \ --without-x \ --without-freetype \ --without-fontconfig \ --without-gettext \ --without-gnutls \ --without-opengl \ --without-vulkan \ --without-sdl \ --without-cups \ --without-coreaudio \ --without-alsa \ --without-pulse \ --without-gstreamer \ --without-ffmpeg \ --without-dbus \ --without-gphoto \ --without-gssapi \ --without-krb5 \ --without-netapi \ --without-opencl \ --without-pcap \ --without-pcsclite \ --without-sane \ --without-usb \ --without-v4l2 \ --without-wayland \ --without-unwind \ --with-mingw=llvm-mingw ) ``` 在 configure 之后,正常的 Switch 包构建将从该树中编译缺失的记事本可执行文件和 DLL。 从代码库根目录运行: ``` WINE_NX_APP=notepad ./wine-nx-probe/build-switch.sh ``` 其他有用的目标: ``` WINE_NX_APP=gui ./wine-nx-probe/build-switch.sh WINE_NX_APP=curl ./wine-nx-probe/build-switch.sh ``` 暂存的 SD 卡包写入至: ``` wine-nx-probe/build-switch/sd-card/switch/wine ``` 将该包复制或同步至: ``` sdmc:/switch/wine ``` 包助手会打印: ``` Sync mounted SD with: wine-nx-probe/tools/sync-switch-wine-package.sh ``` ## 硬件测试检查清单 1. 使用所需目标构建包,通常是: ``` WINE_NX_APP=notepad ./wine-nx-probe/build-switch.sh ``` 2. 部署 `wine-nx-runtime.nro` 和暂存的 `switch/wine` 包。 3. 在 Switch 上运行。 4. 确认运行时日志以预期的标记开头,例如: ``` [BUILD] nx-batched-present-1 ``` 5. 检查: ``` sdmc:/switch/wine/wine-nx-runtime.log sdmc:/switch/wine/horizon-trace.log ``` 这个标记很重要。在日志显示仍在运行较旧的 NRO 之前,几个性能/调试循环看起来非常令人困惑。 ## 重要文件 运行时和打包: ``` wine-nx-probe/build-switch.sh wine-nx-probe/source/runtime.c wine-nx-probe/source/runtime_platform.c wine-nx-probe/CMakeLists.txt ``` Switch 显示和 USER/GDI 集成: ``` dlls/win32u/winnx_drv.c dlls/win32u/window.c dlls/win32u/dce.c dlls/win32u/sysparams.c dlls/win32u/message.c dlls/win32u/input.c ``` Horizon/NTDLL 底层支持: ``` dlls/ntdll/unix/horizon.c dlls/ntdll/unix/file.c dlls/ntdll/unix/process.c dlls/ntdll/unix/thread.c dlls/ntdll/unix/signal_arm64.c ``` 冒烟测试目标: ``` wine-nx-probe/samples/gui-smoke wine-nx-probe/samples/curl-arm64 ``` ## 下一阶段里程碑 1. 呈现性能 替换或绕过高开销的线性 framebuffer 路径。首选方向: - 用于 Wine 软件窗口表面的 Vulkan/NVK compositor; - 将 DIB/窗口表面上传到 GPU 纹理中; - 在 GPU 上进行弹出窗口/窗口合成; - 每帧呈现一次; - 待 Wine 的 Vulkan 路径足够完善,能够进行真正的 D3D 到 Vulkan 加速后,再支持 DXVK/vkd3d。 备选或底层方案: - deko3d compositor; - 直接进行 block-linear 脏区域转换; - 持久的软件后备存储加上每帧呈现一次。 2. 输入优化 - 键盘/文本输入; - 手柄鼠标模式; - 更好的触摸捕获和焦点处理; - 双击/拖拽行为; - 原生 `WM_TOUCH` 支持(稍后进行)。 3. USER/窗口管理器行为 - 弹出窗口/菜单堆叠; - 所有者/激活边缘情况; - 裁剪和失效处理; - 模态对话框; - 子窗口排序。 4. 更多真实应用程序 在记事本运行更流畅之后,下一个有用的测试目标应该是小型的非网络 GUI 应用程序,它们能够测试对话框、通用控件、编辑控件和文件浏览,而无需首先依赖浏览器引擎或 GPU API。
标签:AArch64, Bash脚本, libnx, Wine, 任天堂Switch, 兼容层, 客户端加密, 系统移植, 请求拦截