☰
Madeira总体架构:一个Mach进程如何承载整个Windows游戏栈
2026/10/3 16:48:34 网站建设 项目流程

Madeira总体架构:一个Mach进程如何承载整个Windows游戏栈

【免费下载链接】MadeiraRun x86-64 Windows PC games on jailed iOS via FEX-Emu + Wine + DXMT项目地址: https://gitcode.com/GitHub_Trending/mad/Madeira

Madeira是一个 iPhone Windows 游戏模拟器,它把 FEX-Emu、Wine 和 DXMT 三大组件装进一个 iOS App 进程里,让未经修改的 x86/x86-64 Windows 游戏直接在手机上运行。本文将带你从"单进程"这个核心设计出发,看懂整个 Windows 游戏栈是如何被一个 Mach 进程层层承载的。

一、为什么是"单进程":iOS 的硬约束

iOS App 沙盒不允许启动独立的外部程序——你不能像桌面那样"拉起一个 wineserver.exe 进程"。于是 Madeira 做了一个关键取舍:

所有东西都活在同一个 Mach 任务里:Wine 的服务端不是进程,而是线程;游戏本身不是进程,而是跑在 pthread 上的"伪进程"。

这一条约束决定了下面所有架构决策。

二、四层软件栈:谁负责什么

Madeira 的栈分成四块,每块各管一件事(完整说明见 README.md):

层组件职责
CPU 翻译FEX-Emu(FEX/子模块)运行时把游戏的 x86/x86-64 代码 JIT 成 ARM64
Windows 系统Wine 11.4(wine/子模块)提供 Windows 运行时;按 ARM64EC 编译,Wine 自身原生运行,只有游戏代码被翻译
老图形 APIDXMT(dxmt/子模块)用 Metal 驱动 Direct3D 9/10/11
新图形 APImadeira-d3d12/自研 D3D12 实现,运行时用 Apple Metal Shader Converter 把 DXIL 转成 Metal 着色器

32 位游戏则通过 WoW64 支持,另有 i386 编译的 Wine 模块农场(docs/WOW64.md)。

三、进程地图:线程代替进程 🧵

这是整个架构最有意思的部分,对应源码都在 app/Madeira/ 下:

3.1 wineserver 变成一条高优先级线程

在桌面上,wineserver是独立进程,客户端通过 Unix socket 找它。iOS 上,WineServerBridge.m 直接调用静态链接进来的wineserver_main(),把它跑在 pthread 里,并用pthread_attr_set_qos_class_np把 QoS 提到USER_INTERACTIVE——注释里记录了真实教训:低优先级 wineserver 曾造成典型的优先级反转,游戏线程每帧大部分时间都卡在等它的回复上(L156-L174)。

客户端与服务器之间也不再走 socket,而是通过socketpair+wineserver_inject_client_fd把文件描述符直接"注入"事件循环(见 WineProcessBridge.m)。

3.2 游戏是一条 pthread,__wine_main就是"启动游戏"

WineProcessBridge.m 中的wine_process_thread(L734)承载整个 Wine "进程":

  1. 准备前缀(Wine prefix,即虚拟的C:\)与环境变量;
  2. 确保 FEX JIT 池已初始化(fex_initialize是启动前置条件);
  3. 调用extern void __wine_main(argc, argv)真正启动游戏——在桌面这是"进程创建",在这里只是函数调用。

线程局部变量(_Thread_local jmp_buf)模拟了每个"进程"的退出语义:游戏退出时 longjmp 回到自己的线程而不是杀死整个 App。

四、CPU 层:FEX-Emu JIT 与"双映射"JIT 池

iOS 有两道墙挡住了 JIT:页面大小是 16KB(不是 4KB),以及只有调试器附加时才允许写+执行内存。

FEXBridge.mm 的解法很精巧——同一个 64MB 内存池,两个视图:

  • RX 视图:由调试器(StikDebug)分配的"读+执行"页;
  • RW 视图:用 Machvm_remap把同一块物理页再映射一份"读+写"。

JIT 编译器往 RW 视图写 ARM64 机器码,CPU 从 RX 视图执行,同一物理页两边一致。mmap 钩子(fex_mmap_hook)拦截所有可执行内存申请,改从这个池子里分配;线程退出则用 longjmp 从系统调用里"逃"出来,绕开调试器会抢先拦截信号的陷阱(L208-L213)。

配套细节:__clear_cache通过sys_icache_invalidate做指令缓存失效;宿主特性按 Apple A15 描述(支持 LSE 原子、RCPC、FlagM,无 SVE)。

五、图形层:两条 Metal 路径

  • D3D9/10/11:走 DXMT 的winemetal.dll/d3d11.dll(ARM64EC 编译),unix 侧静态库libdxmt_combined.a由 App 链接。
  • D3D12:madeira-d3d12/ 提供原生d3d12.dll,运行时把 DXIL 字节码交给 Apple 的 Metal Shader Converter 转成 Metal 着色器(头文件与库在 madeira-d3d12/third_party/metal-shader-converter/)。

音频和视频则经 FFmpeg + VideoToolbox / AudioToolbox 打通(docs/MEDIA.md)。

六、"Windows 装在哪":前缀与 DLL 农场

虚拟 C 盘由打包的 prefix-template.tar.gz 在首次启动时解出(PrefixExtractor.c),wineserver 启动前会先播种注册表模板(17,000+ 键),避免生成空注册表。

所有 Windows 模块是预先编译好的"DLL 农场",按架构分目录:

目录内容
app/Madeira/arm64ec-windows/64 位主战场:Wine/DXMT/D3D12 的 ARM64EC DLL(ntdll.dll、winemetal.dll、madeira_d3d12.dll…)
app/Madeira/aarch64-windows/纯 ARM64 模块,含xtajit.dll(FEX 的 WoW64 翻译器)
app/Madeira/i386-windows/32 位 Wine 模块(WoW64 路径)

七、延伸阅读 📚

  • 构建全景(各组件怎么编译、谁链接谁):docs/BUILDING.md
  • 32 位游戏 WoW64 原理:docs/WOW64.md
  • Steam 客户端(Madeira Dock):docs/MADEIRA_DOCK.md
  • 测试程序(x86/x64/WoW64 探针):tests/

一句话总结

Madeira 的本质是用 Mach 原语把三个本应独立的世界压进一个任务:vm_remap双映射解决 JIT,pthread 替代 wineserver 进程,__wine_main函数调用替代"创建进程"。理解了这个单进程模型,就理解了整个项目在 iOS 上跑 Windows 游戏的全部地基。

【免费下载链接】MadeiraRun x86-64 Windows PC games on jailed iOS via FEX-Emu + Wine + DXMT项目地址: https://gitcode.com/GitHub_Trending/mad/Madeira

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询