ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Madeira 跨架构运行层:Wine、FEX-Emu 与 DXMT 实战指南

Madeira 跨架构运行层:Wine、FEX-Emu 与 DXMT 实战指南 1. 从Madeira这个名字说起一个被低估的跨架构运行层项目第一次看到Madeira这个词大多数人会联想到葡萄牙那个盛产葡萄酒的海岛或者是一种叫马德拉的加强型葡萄酒。但在跨平台运行这个圈子里Madeira 指向的是另一件事——一个围绕 Wine 与 FEX-Emu 构建的、面向 x86-64 应用在非 x86 平台上运行的实验性方案。它和 DXMT 这类 DirectX 到 Metal 的翻译层放在一起看整条链路就清晰了让原本为 Windows/x86-64 编译的程序在 ARM 架构的设备上跑起来并且尽量把图形接口也接上。这个方向为什么值得单独拿出来讲因为过去几年里ARM 设备的性能已经足够强强到很多人开始认真考虑能不能不靠原生移植直接把现成的 x86-64 程序搬过来用。Wine 负责把 Windows 的 API 调用翻译成 POSIX 调用FEX-Emu 负责把 x86-64 指令翻译成 ARM64 指令DXMT 负责把 DirectX 翻译成 Metal。三者叠在一起理论上就能让一个 Windows 游戏或者 Windows 生产力工具在一台 ARM 设备上跑起来。Madeira 就是把这套组合打包、调优、验证的一个具体实践。我关注这个方向有一段时间了踩过的坑不算少。这篇文章不打算写成一份官方文档式的说明而是把我理解的 Madeira 这套东西的来龙去脉、关键组件、实际配置、常见故障和排查思路按一个从业者的视角完整讲一遍。适合谁看如果你在做 ARM 平台上的兼容层、在折腾 Wine 跑 Windows 程序、或者单纯对x86-64 程序怎么在 ARM 上跑这件事好奇这篇内容应该能给你一些可以直接上手的东西。关键词里出现的 Wine、FEX-Emu、DXMT、x86-64 这几个词基本就是全文的主线我会围绕它们把整条技术链路拆开讲。2. 拆解 Madeira 的技术栈Wine、FEX-Emu、DXMT 各自扮演什么角色2.1 Wine 不是模拟器它是 API 翻译层很多人第一次接触 Wine 会误以为它是个虚拟机或者模拟器其实不是。Wine 的全称是 Wine Is Not an Emulator它做的事情是把 Windows 的 API 调用比如 kernel32、user32、ntdll 这些 DLL 导出的函数在运行时翻译成对应的 POSIX 调用。也就是说一个 Windows 程序在 Wine 里跑的时候它调用的还是它自己编译出来的 x86-64 指令只是这些指令里对 Windows 系统的请求被 Wine 拦截并转成了 Linux 或 macOS 能理解的系统调用。这个区别非常关键。因为 Wine 不翻译指令所以它本身不解决架构问题。一个 x86-64 的 Windows 程序在 x86-64 的 Linux 上跑Wine 直接就能工作但到了 ARM64 设备上Wine 就无能为力了因为 CPU 根本看不懂 x86-64 指令。这时候就需要 FEX-Emu 出场。Wine 的另一个特点是它的实现是渐进式的。Windows API 浩如烟海Wine 不可能一次性全部实现所以它采取的是按需实现、逐步补齐的策略。这就导致一个现象有些程序在 Wine 上跑得非常好有些程序一启动就崩差别往往就在于那个程序用到了哪些还没被完整实现的 API。这也是为什么 Wine 的版本更新对兼容性影响很大每次大版本更新都可能让一批原本跑不了的程序突然能跑了。2.2 FEX-Emu 解决的是指令集翻译问题FEX-Emu 是一个 x86-64 到 ARM64 的指令翻译层。它的工作方式是把 x86-64 的机器码在运行时翻译成 ARM64 的机器码然后交给 ARM CPU 执行。这个过程叫动态二进制翻译Dynamic Binary TranslationDBT。和传统的全系统模拟器不同FEX-Emu 是用户态的它不需要模拟整个硬件环境只需要处理指令翻译和必要的系统调用转发。FEX-Emu 的性能表现取决于几个因素。第一是翻译缓存的命中率如果一个代码块被反复执行翻译一次之后缓存起来后续就直接用缓存速度会快很多。第二是 x86-64 和 ARM64 之间的语义差异比如内存模型、浮点行为、原子操作这些处理不好就会导致程序行为异常或者性能下降。第三是它对 x86-64 扩展指令集的支持程度比如 AVX、AVX2 这些支持得越全能跑的程序就越多。在实际使用中FEX-Emu 通常和 Wine 配合使用Wine 提供 Windows API 的翻译FEX-Emu 提供指令集的翻译两者叠加才能让一个 x86-64 的 Windows 程序在 ARM64 设备上跑起来。Madeira 这个项目要做的就是把这两者的配合调到一个可用的状态。2.3 DXMT 补上图形这一环程序能跑起来是一回事能正常显示画面是另一回事。Windows 程序尤其是游戏大量使用 DirectX 来做图形渲染。在 ARM 设备上图形接口通常是 MetalApple 平台或者 VulkanLinux/Android 平台。DXMT 的作用就是把 DirectX 的调用翻译成 Metal 的调用让 Windows 程序的图形渲染能在 Apple 的 GPU 上执行。DXMT 主要针对的是 DirectX 11 及以下版本。DirectX 12 的翻译要复杂得多因为 DX12 暴露了更多底层细节翻译层需要处理命令队列、描述符堆、根签名这些概念工作量大很多。所以如果你打算用 Madeira 跑游戏先确认一下目标游戏用的是 DX11 还是 DX12这直接决定了它能不能跑起来。把这三个组件放在一起看Madeira 的技术栈就清楚了FEX-Emu 在最底层做指令翻译Wine 在中间层做 API 翻译DXMT 在上层做图形翻译。三层各司其职缺一不可。理解了这个分层后面遇到问题的时候你就能快速判断问题出在哪一层。组件职责解决的问题不解决的问题FEX-Emux86-64 到 ARM64 指令翻译CPU 架构不兼容Windows API 不存在WineWindows API 到 POSIX 翻译系统调用不兼容CPU 架构不兼容DXMTDirectX 到 Metal 翻译图形接口不兼容指令集和 API 问题3. 实际部署 Madeira从环境准备到跑通第一个程序3.1 环境准备中最容易被忽略的几个细节部署 Madeira 之前有几个前置条件必须先确认清楚否则后面会浪费大量时间在排查环境问题上。第一是系统版本。FEX-Emu 对内核版本有要求因为它依赖一些较新的系统特性来做内存管理和信号处理。如果你用的是比较老的发行版建议先升级内核。第二是架构确认你的设备必须是 ARM64 的用uname -m确认输出是aarch64而不是x86_64。第三是图形驱动DXMT 依赖 Metal所以这套方案主要面向 Apple 平台如果你在 Linux ARM 设备上图形翻译要走别的路线。还有一个容易被忽略的点是文件系统的大小写敏感性。Windows 程序默认文件系统不区分大小写而 Linux 默认区分。Wine 通过一些机制来模拟不区分大小写的行为但在某些边缘情况下还是会出现找不到文件的问题。如果你遇到文件明明存在却报找不到的情况先检查一下大小写。提示在开始部署之前先用一个最简单的 Windows 程序比如记事本做验证确认基础链路是通的再去跑复杂的程序。这样能把问题范围缩小。3.2 组件安装顺序与依赖关系安装顺序很重要因为组件之间有依赖关系。推荐的顺序是先装 FEX-Emu再装 Wine最后装 DXMT。FEX-Emu 先装是因为它是基础运行环境Wine 的运行需要它提供的 x86-64 执行能力。安装 FEX-Emu 的时候要注意 rootfs 的配置它需要一个 x86-64 的根文件系统来提供基础的库文件。这个 rootfs 可以从发行版官方获取也可以用工具生成。rootfs 的完整性直接影响后续程序能不能跑起来如果缺库程序会在启动阶段就报错。Wine 的安装相对直接但要注意选择正确的版本。Wine 有 stable、staging、devel 几个分支staging 分支包含了一些还没进入主线的补丁对某些程序的兼容性更好但也可能引入新的问题。如果你追求稳定先用 stable如果遇到兼容性问题再考虑换 staging。DXMT 的安装需要编译因为它通常不以二进制包的形式分发。编译之前要确认 Metal 开发工具链是完整的Xcode Command Line Tools 要装好。编译过程中如果报链接错误多半是 Metal 框架的路径没配置对。3.3 跑通第一个程序的完整验证流程环境装好之后不要急着跑游戏先用一个简单的程序验证整条链路。我一般用 Windows 自带的记事本或者一个简单的控制台程序来做验证。第一步确认 FEX-Emu 能正常工作。找一个 x86-64 的 Linux 二进制程序用 FEX-Emu 跑一下看能不能正常执行。这一步验证的是指令翻译层。第二步确认 Wine 能正常工作。用 Wine 跑一个简单的 Windows 控制台程序看能不能输出结果。这一步验证的是 API 翻译层。第三步确认图形链路能正常工作。用 Wine 跑一个带窗口的 Windows 程序看窗口能不能正常显示。这一步验证的是图形翻译层。这三步都通过之后再上复杂的程序。如果某一步失败就集中排查那一层的问题不要跳步。我见过太多人一上来就跑大型游戏结果报了一堆错根本不知道问题出在哪一层。4. 那些让人抓狂的典型故障乱码、崩溃与图形异常4.1 Wine 乱码问题的根源与修复Wine 乱码是搜索热词里出现频率很高的问题我把它放在第一个讲因为它太常见了。乱码的表现形式有好几种菜单栏文字变成方块、程序界面文字变成问号、控制台输出变成乱码。不同的表现形式根源不一样。菜单栏和界面文字乱码通常是字体缺失导致的。Wine 需要中文字体来渲染中文界面如果系统里没有安装合适的中文字体Wine 就会用默认字体去渲染结果就是方块或者乱码。解决办法是安装中文字体并且配置 Wine 的字体替换规则把 Windows 常用的字体比如 SimSun、Microsoft YaHei映射到系统里已有的中文字体上。控制台输出乱码通常是编码问题。Windows 控制台默认使用 GBK 或者 CP936 编码而 Linux 终端默认使用 UTF-8。当 Wine 把 Windows 程序的输出转发到 Linux 终端时如果编码没有正确转换就会出现乱码。解决办法是设置LANG和LC_ALL环境变量或者在 Wine 的配置里指定正确的代码页。还有一种乱码是Wine 栏是乱码这个通常指的是 Wine 的窗口标题栏或者菜单栏显示异常。这往往和 Wine 的主题配置有关Wine 默认使用内置的主题如果主题文件缺失或者配置错误就会导致界面元素渲染异常。解决办法是检查 Wine 的 theme 配置必要时重置为默认主题。注意乱码问题不要盲目改配置先确定是哪一类乱码再对症下药。改之前备份配置文件改错了还能回退。4.2 程序启动即崩溃的排查链路程序启动就崩溃是另一个高频问题。排查这类问题我习惯按下面的链路走。先看崩溃发生在哪个阶段。如果程序还没进入 Wine 就崩了那问题在 FEX-Emu 或者系统环境。如果程序进入了 Wine 但在初始化阶段崩了那问题在 Wine 的 API 实现或者依赖库。如果程序进入了图形初始化阶段才崩那问题在 DXMT 或者图形驱动。看日志。Wine 的日志可以通过WINEDEBUG环境变量来控制设置WINEDEBUGall可以输出所有调试信息但信息量巨大建议先用WINEDEBUGerr只看错误。FEX-Emu 也有自己的日志输出可以设置日志级别来查看指令翻译过程中的异常。用最小复现来定位。如果一个大程序崩溃先找一个功能类似的小程序来测试看是不是同样崩溃。如果小程序正常那问题可能出在大程序特有的功能上如果小程序也崩溃那问题在基础环境。检查依赖库。用ldd或者类似的工具检查程序依赖的动态库是否齐全缺库是导致启动崩溃的常见原因。Wine 有自己的库搜索路径有时候系统里有库但 Wine 找不到需要手动配置。4.3 图形渲染异常的几种典型表现图形异常的表现形式很多我挑几种典型的讲。黑屏是最常见的。程序启动了窗口也出来了但内容全黑。这通常是 DXMT 的翻译出了问题或者 Metal 的渲染管线没有正确初始化。排查的时候先确认 DXMT 的日志有没有报错再看 Metal 的验证层有没有输出警告。花屏或者画面撕裂通常是渲染同步问题。DXMT 在翻译 DirectX 的呈现调用时如果和 Metal 的显示同步机制配合不好就会出现这类问题。可以尝试调整 DXMT 的同步相关配置或者关闭一些渲染优化选项。帧率异常低可能是翻译缓存的命中率太低也可能是某个渲染路径走了低效的实现。FEX-Emu 和 DXMT 都有性能相关的配置项可以逐个调整来定位瓶颈。纹理丢失或者贴图错误通常是格式转换问题。DirectX 和 Metal 支持的纹理格式不完全一致DXMT 在转换过程中如果遇到不支持的格式就可能出现纹理丢失。这类问题往往需要等 DXMT 更新支持或者手动转换纹理格式。故障表现可能原因排查方向界面文字方块中文字体缺失安装字体并配置替换规则控制台乱码编码不匹配设置 LANG/LC_ALL 或代码页启动即崩溃依赖库缺失或 API 未实现检查 ldd 和 WINEDEBUG 日志黑屏DXMT 翻译失败查看 DXMT 日志和 Metal 验证层帧率过低翻译缓存命中率低调整 FEX-Emu 缓存配置5. 性能调优让 x86-64 程序在 ARM 上跑得更顺5.1 FEX-Emu 的缓存策略与调优参数FEX-Emu 的性能很大程度上取决于翻译缓存的效率。它的工作模式是第一次遇到一段 x86-64 代码时把它翻译成 ARM64 代码并缓存起来后续再遇到同一段代码直接使用缓存。所以缓存的大小和命中率直接影响性能。FEX-Emu 提供了几个和缓存相关的配置项。缓存大小决定了能存多少翻译后的代码缓存太小会导致频繁的缓存淘汰和重新翻译性能下降明显。在多核设备上还可以配置多线程翻译让翻译工作和执行工作并行减少等待时间。还有一个重要的参数是 JITJust-In-Time编译的优化级别。FEX-Emu 在翻译代码时可以做不同级别的优化优化级别越高翻译出来的代码执行越快但翻译本身耗时也越长。对于长时间运行的程序高优化级别是值得的对于短时间运行的程序低优化级别可能更合适。实测下来对于游戏这类长时间运行、代码热区集中的程序把缓存调大、优化级别调高帧率提升是肉眼可见的。对于命令行工具这类短时间运行的程序默认配置通常就够了。5.2 DXMT 的渲染路径选择DXMT 在翻译 DirectX 调用时有几种不同的渲染路径可以选择。不同的路径在兼容性和性能上各有取舍。一种路径是直接映射把 DirectX 的调用尽可能直接地映射到 Metal 的对应调用上。这种路径性能最好但要求 DirectX 和 Metal 的功能集有足够的重叠遇到不重叠的部分就需要回退。另一种路径是模拟对于 Metal 没有直接对应的 DirectX 功能用多个 Metal 调用组合来模拟。这种路径兼容性更好但性能会有损失。DXMT 通常会根据程序的实际调用来动态选择路径但也提供了一些配置项来强制指定。如果你遇到某个程序在默认配置下性能不理想可以尝试调整这些配置看看能不能找到更合适的路径。5.3 系统层面的配合优化除了组件本身的调优系统层面也有一些可以做的优化。CPU 调度策略会影响 FEX-Emu 的性能。FEX-Emu 的翻译线程和执行线程如果被调度到不同的核心上可能会因为缓存不共享而性能下降。可以通过设置 CPU 亲和性把相关线程绑定到同一簇核心上。内存管理也会影响性能。FEX-Emu 需要维护 x86-64 和 ARM64 之间的内存映射如果内存分配策略不合理会导致频繁的页错误和映射切换。可以调整系统的内存管理参数减少这类开销。图形驱动的版本也很关键。Metal 的性能和功能随驱动版本更新而变化较新的驱动通常有更好的性能和更多的功能支持。如果 DXMT 用到了某些较新的 Metal 特性旧驱动可能不支持导致回退到低效路径。6. 从 Madeira 延伸出去这套方案还能用在哪些场景6.1 不只是游戏生产力工具的跨架构运行虽然大家讨论 Wine 和 FEX-Emu 的时候焦点往往在游戏上但这套方案对生产力工具同样有价值。很多行业软件只有 Windows 版本没有 Linux 或 macOS 版本在 ARM 设备上更是完全没有原生支持。通过 Madeira 这套组合这些软件理论上也能在 ARM 设备上跑起来。当然生产力工具对稳定性的要求比游戏更高。游戏崩了可以重开生产力工具崩了可能意味着数据丢失。所以在用这套方案跑生产力工具的时候要特别注意数据保存和恢复机制不要在没有备份的情况下处理重要数据。另外生产力工具往往涉及更多的系统集成比如打印机、扫描仪、专业外设这些。Wine 对这些外设的支持程度参差不齐有些能直接用有些需要额外的配置有些则完全用不了。在决定用这套方案之前先确认你的关键外设能不能在 Wine 里正常工作。6.2 开发调试场景下的应用对于开发者来说Madeira 这套方案还有一个用途在没有 x86-64 硬件的情况下测试 x86-64 程序的 ARM 兼容性。比如你在开发一个跨平台应用想确认它在 ARM 设备上的表现但又没有 ARM 设备就可以用这套方案在 x86-64 机器上模拟 ARM 环境反过来用。不过要注意这种模拟测试的结果和真实 ARM 设备上的结果可能有差异因为模拟环境下的时序、内存行为、图形驱动都和真实设备不同。所以模拟测试只能作为参考最终验证还是要在真实设备上做。6.3 这套技术栈的局限性与边界说了这么多这套方案能做什么也得说清楚它不能做什么。首先不是所有 x86-64 程序都能跑。有些程序用了 FEX-Emu 还没支持的指令集扩展有些程序用了 Wine 还没实现的 Windows API有些程序用了 DXMT 还没翻译的 DirectX 功能。遇到这些情况只能等上游更新或者找替代方案。其次性能永远不可能达到原生水平。指令翻译和 API 翻译都有开销这是物理规律决定的。对于性能敏感的应用这套方案可能不合适。最后这套方案的维护成本不低。组件之间的版本兼容性、配置的调优、故障的排查都需要投入时间和精力。如果你只是偶尔用一下某个 Windows 程序可能用虚拟机更省事如果你需要长期、高频地使用那投入时间调优这套方案才是值得的。7. 我在实际折腾中积累的几条经验折腾 Madeira 这套东西的过程中我积累了一些文档里不会写的经验分享几条。第一条版本锁定很重要。Wine、FEX-Emu、DXMT 这三个组件的版本组合不是随便哪个版本搭配都能工作的。有时候新版本修了一个问题却引入了另一个问题。所以一旦找到一组能正常工作的版本组合就把它记下来不要轻易升级。如果非要升级先在一个独立的环境里测试确认没问题再迁移。第二条日志是你的朋友。遇到问题的时候不要凭感觉猜先看日志。Wine 的WINEDEBUG、FEX-Emu 的日志输出、DXMT 的调试信息这些都能帮你快速定位问题。我习惯在跑新程序之前先把日志级别调高这样出问题的时候有足够的信息可以分析。第三条社区是最好的文档。这套方案的官方文档往往滞后于实际发展很多最新的兼容性信息和配置技巧都在社区里。遇到问题的时候先搜一下有没有人遇到过类似的情况往往能省下大量时间。第四条不要追求完美。这套方案的目标是能用不是完美。有些小问题比如偶尔的界面闪烁、轻微的音画不同步可能不值得花大量时间去修。把精力放在关键问题上比如程序能不能启动、核心功能能不能用这些才是决定这套方案是否可用的关键。第五条做好备份。折腾这套方案的过程中配置文件会被反复修改系统环境也可能被改动。在开始折腾之前先备份好配置文件和重要数据这样即使折腾出问题了也能快速恢复。最后再分享一个小技巧如果你在跑某个程序的时候遇到问题可以试试换一个 Wine 的 Windows 版本模拟。Wine 可以模拟不同版本的 Windows有些程序在 Windows 7 模式下能跑在 Windows 10 模式下反而跑不了反之亦然。这个设置通常在winecfg里就能改值得一试。
返回列表