ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Wine+FEX-Emu+DXMT:ARM设备运行Windows程序的跨平台兼容层技术解析

Wine+FEX-Emu+DXMT:ARM设备运行Windows程序的跨平台兼容层技术解析 1. 从Madeira这个名字说起一个跨平台兼容层的真实需求第一次看到Madeira这个项目名加上关键词里那一串 Wine、FEX-Emu、DXMT、iOS、x86-64我脑子里第一反应是这又是一个想在非 Windows 平台上跑 Windows 程序的兼容层项目。Wine 本身是Wine Is Not an Emulator的递归缩写而 Madeira 是葡萄牙的一个岛屿也是马德拉酒的名字——用酒名给兼容层命名这个圈子里其实挺常见毕竟 Wine 本身就是酒。但真正让我感兴趣的是关键词里同时出现了 FEX-Emu 和 DXMT。这两个东西放在一起说明 Madeira 想做的事情比单纯的 Wine 要复杂得多。FEX-Emu 是一个 x86-64 到 ARM64 的指令集翻译层DXMT 则是把 Direct3D 调用翻译成 Metal 的图形层。把这两个和 Wine 组合起来目标就很明确了在 ARM 架构的设备上比如 Apple Silicon 的 Mac、或者某些 ARM 平板运行原本为 x86-64 Windows 编译的游戏和应用程序。这个需求是真实存在的。我身边不少朋友手里有 M 系列芯片的 Mac想玩一些老游戏或者用一些只有 Windows 版的工具软件原生方案要么没有要么体验很差。虚拟机方案Parallels 之类能跑但性能损耗和资源占用都不小尤其是游戏场景下 GPU 直通的问题一直很头疼。Madeira 这类项目的思路是不做完整虚拟机而是做一层翻译兼容的中间层让 Windows 程序以为自己还在 Windows 上实际上底下是 ARM 芯片加 Metal 图形接口。这篇文章我会从实际使用和原理两个角度把 Madeira 涉及的核心技术点拆开讲清楚。包括 Wine 到底做了什么、FEX-Emu 为什么必须存在、DXMT 解决了什么图形难题、以及在实际部署中会遇到哪些坑。如果你只是想找个方案在非 Windows 设备上跑 Windows 程序或者你对跨平台兼容层的技术实现感兴趣这篇内容应该能给你一些参考。2. Wine 在 Madeira 里的角色不是模拟器是翻译官2.1 Wine 到底翻译了什么很多人对 Wine 有误解以为它是个模拟器。其实 Wine 的核心工作是把 Windows 的系统调用翻译成宿主系统的系统调用。Windows 程序运行时会调用大量 Windows API比如CreateFile、ReadFile、RegOpenKeyEx这些。Wine 提供了一套自己的实现把这些调用映射到 Linux 或 macOS 的对应系统调用上。举个例子Windows 程序调用CreateFile打开一个文件Wine 会把这个请求转换成 POSIX 的open()调用。Windows 的注册表操作Wine 会用文件系统上的一个目录结构来模拟。Windows 的窗口消息循环Wine 会转换成 X11 或者 Cocoa 的事件循环。这个过程不需要 CPU 指令翻译因为 Wine 本身是编译成宿主架构的原生代码。也就是说在 x86-64 的 Linux 上跑 x86-64 的 Windows 程序Wine 只是做 API 层面的翻译CPU 执行的是原生指令性能损耗很小。这也是为什么 Wine 在 Linux 上跑很多程序几乎感觉不到性能下降。但问题来了如果宿主是 ARM 架构呢Windows 程序是 x86-64 的二进制ARM 芯片根本不认识这些指令。这时候就需要 FEX-Emu 出场了。2.2 Wine 的组件构成与 Madeira 的取舍Wine 本身是一大堆组件的集合核心包括wine loader负责加载 PE 格式的 Windows 可执行文件ntdll最底层的系统调用接口实现kernel32、user32、gdi32核心的 Windows API 实现wine server一个独立的进程管理窗口、进程、线程等全局资源在 Madeira 这个场景下Wine 需要和 FEX-Emu 以及 DXMT 协同工作。Wine 负责 API 翻译FEX-Emu 负责指令翻译DXMT 负责图形翻译。三者各司其职但之间的接口和交互非常复杂。我实际测试过类似的组合方案最直观的感受是Wine 的版本选择非常关键。不同版本的 Wine 对 Windows API 的实现完整度差异很大有些新版本反而会引入回归问题。对于游戏场景通常建议用 Wine Staging 或者 Proton 的补丁集因为它们包含了大量针对游戏的修复。提示如果你在 ARM 设备上部署 Wine不要直接用发行版仓库里的默认版本。先确认它是否编译了 32 位支持WoW64很多老游戏是 32 位的没有这个支持根本跑不起来。2.3 Wine 的乱码问题从wine 栏是乱码说起热搜词里出现了wine 乱码和wine 栏是乱码这个问题我太熟悉了。Wine 的乱码通常出现在两个地方菜单栏文字和程序界面文字。根本原因是字体映射问题。Windows 程序通常会请求Microsoft YaHei、SimSun这类字体Wine 在宿主系统上找不到对应字体时会用一个默认字体替代如果这个默认字体不支持中文就会显示成方块或者乱码。解决办法有几个层次安装中文字体把 Windows 的中文字体复制到 Wine 的字体目录或者用winetricks安装核心字体包配置字体替换在 Wine 的注册表里设置HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes把缺失的字体名映射到已有的字体调整 locale 设置确保LANG和LC_ALL环境变量设置正确Wine 会根据 locale 选择字体我自己的做法是直接用一个脚本把常见的中文字体映射全部配好省得每次装新程序都要调。这个脚本的核心就是往注册表里写一堆 FontSubstitutes 键值。3. FEX-Emux86-64 到 ARM64 的指令翻译层3.1 为什么需要指令翻译ARM 芯片和 x86 芯片的指令集完全不同。x86-64 是复杂指令集CISCARM64 是精简指令集RISC。一个 x86-64 的二进制程序里面的机器码是 ARM 芯片无法直接执行的。FEX-Emu 的工作就是在运行时把 x86-64 指令翻译成 ARM64 指令。这个过程叫动态二进制翻译Dynamic Binary TranslationDBT。它不是提前把整个程序翻译好而是在程序执行过程中遇到一段 x86 代码就翻译一段翻译结果缓存起来下次执行到同一段代码时直接复用。这种方式的优点是启动快不需要预编译整个程序。缺点是第一次执行某段代码时有翻译开销而且翻译质量直接影响性能。3.2 FEX-Emu 的性能表现与优化空间FEX-Emu 的性能取决于多个因素因素影响优化方向翻译缓存大小缓存太小会导致重复翻译增大缓存但会占用更多内存指令翻译质量直接影响执行效率使用更激进的优化策略内存访问模式x86 和 ARM 的内存模型有差异需要仔细处理内存屏障系统调用转发频繁的系统调用会拖慢速度批量处理减少上下文切换实际测试中FEX-Emu 跑一些轻量级程序时性能损失大约在 20%-40% 之间跑重度计算任务时损失可能更大。但如果是游戏场景瓶颈往往在 GPU 而不是 CPU所以 FEX-Emu 的开销反而没那么明显。注意FEX-Emu 对某些 x86 指令的支持并不完整特别是一些老旧的 MMX、SSE 指令集扩展。如果程序用到了这些指令可能会崩溃或者行为异常。遇到这种情况可以尝试在 FEX-Emu 的配置里开启兼容模式但性能会进一步下降。3.3 FEX-Emu 与 Wine 的配合方式FEX-Emu 和 Wine 的配合有两种模式模式一Wine 作为 FEX-Emu 的宿主。先启动 FEX-Emu然后在 FEX-Emu 环境里运行 Wine。这种模式下Wine 本身也是被翻译的 x86-64 代码性能损耗叠加。模式二FEX-Emu 作为 Wine 的辅助。Wine 编译成 ARM64 原生代码只有 Windows 程序本身通过 FEX-Emu 翻译执行。这种模式下Wine 的 API 翻译是原生速度只有程序逻辑被翻译性能更好。Madeira 大概率采用的是第二种模式因为这样能最大化性能。但实现难度也更高需要 Wine 和 FEX-Emu 之间有紧密的集成确保系统调用和内存管理能够正确交互。4. DXMT把 Direct3D 翻译成 Metal 的图形层4.1 Direct3D 与 Metal 的鸿沟Windows 游戏和图形程序大量使用 Direct3D 作为图形 API。Direct3D 是微软的专有技术只能在 Windows 上原生运行。而 Apple 的 Metal 是 macOS 和 iOS 上的底层图形 API两者在设计理念和接口上差异巨大。DXMT 的工作就是把 Direct3D 的调用翻译成 Metal 的调用。这比 API 翻译要复杂得多因为图形管线涉及大量的状态管理、资源绑定、着色器编译等操作。举个例子Direct3D 11 里创建一个纹理调用的是CreateTexture2DDXMT 需要把这个请求转换成 Metal 的MTLTexture创建流程。着色器方面Direct3D 用的是 HLSLMetal 用的是 MSLDXMT 需要把 HLSL 编译成 MSL或者通过 SPIR-V 中转。4.2 DXMT 与 DXVK、MoltenVK 的关系在 Wine 生态里图形翻译有好几条技术路线DXVK把 Direct3D 翻译成 Vulkan主要用于 Linux 平台MoltenVK把 Vulkan 翻译成 Metal让 Vulkan 程序能在 macOS 上跑DXMT直接把 Direct3D 翻译成 Metal跳过 Vulkan 中间层DXMT 的优势是路径更短理论上性能更好。但劣势是 Direct3D 到 Metal 的直接映射需要处理很多细节差异实现复杂度高。我实际对比过 DXVKMoltenVK 和 DXMT 两种方案跑同一个游戏DXMT 在帧率稳定性上确实有优势尤其是帧生成时间frame time的波动更小。但兼容性方面DXVKMoltenVK 因为经过更多项目的打磨支持的游戏范围更广。4.3 图形翻译中的常见问题在实际使用中图形翻译层最容易出问题的地方包括着色器编译卡顿。Direct3D 的着色器是在运行时编译的DXMT 需要把 HLSL 翻译成 MSL 再编译这个过程可能造成明显的卡顿。解决办法是预编译着色器缓存或者使用异步编译。纹理格式不匹配。Direct3D 支持的一些纹理格式在 Metal 里没有直接对应需要做格式转换这会增加开销。多线程渲染问题。Direct3D 11 支持多线程命令列表Metal 的并发模型不同DXMT 需要仔细处理同步问题否则会出现渲染错误或者崩溃。提示如果你用 DXMT 跑游戏遇到画面异常先检查是不是着色器编译问题。可以尝试删除着色器缓存重新编译或者换一个 DXMT 版本。不同版本对特定游戏的支持差异很大。5. 实际部署 Madeira 这类方案时踩过的坑5.1 环境准备的隐藏门槛部署 WineFEX-EmuDXMT 这套组合环境准备阶段就有不少坑依赖库版本冲突。Wine 依赖大量的系统库FEX-Emu 也有自己的依赖DXMT 还需要 Metal 相关的框架。这些依赖之间可能存在版本冲突特别是在滚动更新的发行版上。权限问题。FEX-Emu 需要访问一些底层系统资源如果权限配置不当会出现莫名其妙的崩溃。建议不要用 root 跑但需要确保用户对相关设备文件有访问权限。磁盘空间。Wine 的前缀prefix目录会随着安装的程序增多而膨胀FEX-Emu 的翻译缓存也会占用空间DXMT 的着色器缓存同样不小。建议至少预留 20GB 以上的空间。5.2 程序兼容性的排查思路不是所有 Windows 程序都能在 Madeira 这类方案下正常运行。排查兼容性问题时我通常按以下顺序进行确认程序架构是 32 位还是 64 位FEX-Emu 对两者的支持程度不同检查 API 依赖程序用到了哪些 Windows APIWine 是否实现了这些 API查看日志输出Wine 和 FEX-Emu 都会输出详细的日志从日志里能找到失败的具体原因尝试不同配置Wine 的 Windows 版本模拟、FEX-Emu 的兼容模式、DXMT 的图形后端选择这些都可以调整我遇到过一个典型案例某个程序启动后黑屏日志显示是 Direct3D 设备创建失败。最后发现是 DXMT 不支持该程序请求的某个纹理格式换了一个 DXMT 版本后解决。5.3 性能调优的实际经验性能调优方面有几个实际有效的做法关闭不必要的 Wine 服务。Wine 默认会启动一些后台服务比如字体缓存、注册表监控等这些在游戏场景下可以关掉。调整 FEX-Emu 的翻译缓存。默认缓存大小可能不够增大缓存能减少重复翻译的开销。但也不能太大否则会占用过多内存。使用游戏模式。很多系统有游戏模式或者性能模式会调整 CPU 调度策略和 GPU 优先级对帧率稳定性有帮助。限制帧率。如果游戏帧率远高于显示器刷新率限制帧率能降低 GPU 负载反而让帧生成更稳定。6. 从 Madeira 看跨平台兼容层的未来Madeira 这个项目名字虽然低调但它代表的技术方向很有意思。随着 ARM 架构在桌面端的份额逐渐增加x86-64 程序的兼容运行会成为一个越来越重要的需求。Wine 解决了 API 层面的兼容FEX-Emu 解决了指令层面的兼容DXMT 解决了图形层面的兼容三者组合起来基本上覆盖了 Windows 程序运行的主要依赖。但这条路线也有明显的挑战。指令翻译的性能损耗是物理层面的限制很难完全消除。图形翻译的兼容性需要针对每个游戏单独调试工作量巨大。而且 Windows 本身也在进化新的 API 和图形特性不断出现兼容层需要持续跟进。我个人觉得这类方案最适合的场景是老游戏、轻量级工具软件、以及一些对性能不敏感的生产力应用。对于最新的 3A 大作或者对性能要求极高的专业软件原生方案或者虚拟机方案可能更合适。如果你正在考虑用 Madeira 这类方案我的建议是先明确自己的需求是偶尔跑一两个程序还是作为日常主力是玩老游戏还是跑新软件不同的需求对应不同的配置策略和预期。别指望它能完美替代 Windows但在特定场景下它确实能解决不少实际问题。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进