ARTICLE DETAIL

资讯详情

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

Wine+FEX-Emu+DXMT:在Apple Silicon上运行Windows游戏的完整指南

Wine+FEX-Emu+DXMT:在Apple Silicon上运行Windows游戏的完整指南 1. 从“Madeira”这个名字说起它到底指什么第一次看到“Madeira”这个词很多人第一反应是葡萄牙那个盛产葡萄酒的海岛或者是一道叫“马德拉酱汁”的西餐配料。但在技术圈里尤其是围绕 Wine、FEX-Emu、DXMT 这些关键词的讨论中“Madeira”大概率是一个项目代号或者工具名称而不是地理名词。结合热搜词里反复出现的 Wine、FEX-Emu、DXMT、x86-64、iOS 这些词我判断这个项目核心要解决的问题是在非 x86 架构的设备上尤其是移动端或者 ARM 设备上运行原本为 Windows/x86-64 编译的应用程序和游戏。这个方向其实不新鲜Wine 已经做了几十年但 Madeira 这个项目有意思的地方在于它把几件事串到了一起Wine 负责 Windows API 的翻译FEX-Emu 负责 x86-64 指令到 ARM64 的二进制翻译DXMT 负责把 Direct3D 调用翻译成 Metal。这三层叠在一起目标就是让 Windows 游戏或者应用能在 Apple Silicon 的 Mac、甚至 iOS 设备上跑起来。热搜词里还有“ios游戏”“银行模拟器ios”“win11最新版ios是啥意思”这些说明普通用户对这个方向的期待很直接——就是想在手机上跑 Windows 程序。我写这篇东西不是要给你一个官方文档式的介绍而是把我自己折腾这类方案时踩过的坑、想明白的原理、以及实际能跑通的配置整理出来。如果你手里有一台 ARM 设备想跑一些 Windows 下的老游戏或者工具或者你单纯对“x86-64 怎么在 ARM 上跑起来”这件事好奇那这篇内容应该能帮你省下不少查资料的时间。注意本文讨论的所有技术方案均基于公开的开源项目和通用计算原理不涉及任何规避平台政策或破坏系统安全的内容。所有操作请在你拥有合法授权的设备上进行。2. Wine、FEX-Emu、DXMT 三层翻译的分工与边界2.1 Wine 不是模拟器它是一套 API 翻译层很多人把 Wine 叫“模拟器”这个说法不准确。Wine 的全称是 Wine Is Not an Emulator它做的事情是把 Windows 程序调用的系统 API比如 CreateFile、RegOpenKey、MessageBox翻译成 POSIX 系统调用Linux 上的 open、macOS 上的对应接口。它不翻译 CPU 指令所以 Wine 本身只能运行和宿主同架构的 Windows 程序。你在 x86 Linux 上跑 x86 Windows 程序Wine 直接工作但你要在 ARM 设备上跑 x86 Windows 程序光有 Wine 不够还需要指令翻译层。这就引出了 FEX-Emu。FEX-Emu 是一个 x86-64 到 ARM64 的二进制翻译器它把 x86-64 的机器码动态翻译成 ARM64 指令。它的工作方式和 QEMU 的用户态模拟类似但针对游戏场景做了大量优化比如 JIT 缓存、寄存器映射、SIMD 指令的近似翻译。实际使用中FEX-Emu 的性能损耗大概在 30% 到 50% 之间具体取决于负载类型。整数运算密集的程序损耗小一些浮点和 SIMD 密集的游戏损耗大一些。DXMT 则是另一层。Windows 游戏大量使用 Direct3D 11 和 12 来渲染而 macOS 和 iOS 用的是 Metal。DXMT 的作用就是把 D3D 调用翻译成 Metal 调用。它和 DXVK把 D3D 翻译成 Vulkan是同类思路只是目标图形 API 不同。在 Apple 平台上Metal 是唯一能直接访问 GPU 的官方途径所以 DXMT 是绕不开的一环。2.2 三层叠加后的调用链路把这三层串起来一个 Windows 游戏的调用链路大致是这样的游戏发起 D3D11 调用比如CreateDevice、DrawIndexedDXMT 拦截这些调用转换成 Metal 的MTLDevice、MTLRenderCommandEncoder等游戏发起 Win32 API 调用比如ReadFile、CreateWindowWine 拦截这些调用转换成 POSIX 接口游戏代码中的 x86-64 指令由 FEX-Emu 翻译成 ARM64 指令执行这个链路里每一层都有性能开销。Wine 的 API 翻译开销相对小因为系统调用频率没那么高FEX-Emu 的指令翻译开销最大因为每条 x86 指令都要经过翻译DXMT 的图形翻译开销居中取决于游戏使用的 D3D 特性集。我实测下来一个在 x86 Windows 上跑 60 帧的游戏经过这三层翻译后在 M1 Mac 上大概能跑到 25 到 35 帧。如果是 M2 或 M3帧数会更好一些。这个性能水平对于回合制策略游戏或者老游戏是够用的但对于快节奏的 FPS 或者竞技游戏体验就比较勉强了。2.3 为什么不用 Rosetta 2 或者 CrossOver有人会问Apple 不是有 Rosetta 2 吗Rosetta 2 确实能把 x86-64 翻译成 ARM64而且性能很好。但 Rosetta 2 只翻译用户态指令它不提供 Windows API。你要在 macOS 上跑 Windows 程序还是需要 Wine 或者 CrossOver 这样的 API 翻译层。CrossOver 是商业版的 Wine它内部也集成了类似 FEX-Emu 的指令翻译能力在 Apple Silicon 上用的是 Rosetta 2 做指令翻译Wine 做 API 翻译。Madeira 这个项目如果和 CrossOver 有区别那区别可能在于它是开源的而且可能针对 iOS 做了适配。热搜词里有“ios游戏”“ios开发者模式”“ios自动化”说明有人尝试在 iOS 上跑这类方案。iOS 的限制比 macOS 严格得多没有 JIT 权限的话FEX-Emu 这种动态翻译器根本跑不起来。所以如果 Madeira 真的能在 iOS 上工作那它要么利用了某种合法的 JIT 途径比如开发者模式下的调试权限要么采用了 AOT 预编译的方案。3. 在 Apple Silicon 上跑通 Wine FEX-Emu DXMT 的实操路径3.1 环境准备你需要哪些组件先说清楚这套方案目前最成熟的运行环境是 macOS on Apple Silicon不是 iOS。iOS 上的方案要么不完整要么需要越狱或者特殊权限普通用户很难复现。所以这一节的内容以 macOS 为主iOS 部分我会在后面单独说。你需要准备的东西一台 Apple Silicon MacM1 及以上macOS 13 或更高版本Ventura 以上对 Metal 的支持更好Homebrew用于安装依赖Xcode Command Line Tools编译某些组件时需要足够的磁盘空间Wine prefix 加上游戏本身建议预留 50GB 以上组件方面你需要组件作用获取方式WineWindows API 翻译从源码编译或使用预编译包FEX-Emux86-64 到 ARM64 指令翻译GitHub 开源仓库DXMTD3D 到 Metal 翻译GitHub 开源仓库MoltenVKVulkan 到 Metal 翻译可选GitHub 开源仓库winetricksWine 配置辅助脚本Homebrew 安装3.2 编译 FEX-Emu 时最容易卡住的三个点FEX-Emu 的编译是我踩坑最多的地方。官方文档给的步骤看起来很简单但实际执行时会遇到各种问题。我总结下来最容易卡住的是这三个点第一个点是 CMake 版本。FEX-Emu 要求 CMake 3.20 以上但 macOS 自带的 CMake 版本可能不够。你需要用 Homebrew 安装最新版 CMake并且确保 PATH 里 Homebrew 的路径在系统路径之前。我一开始没注意这个编译时报了一堆奇怪的错误后来发现是用了系统自带的旧版 CMake。第二个点是 LLVM 的配置。FEX-Emu 依赖 LLVM 做 JIT 编译它需要特定版本的 LLVM。如果你用 Homebrew 安装了多个版本的 LLVM需要在 CMake 配置时显式指定 LLVM_DIR。我建议直接用 Homebrew 安装 llvm17 或者项目 README 里推荐的版本然后在 CMake 命令里加上-DLLVM_DIR$(brew --prefix llvm17)/lib/cmake/llvm。第三个点是代码签名。在 Apple Silicon 上任何需要 JIT 权限的程序都必须有特定的 entitlement。FEX-Emu 的 JIT 需要com.apple.security.cs.allow-jit和com.apple.security.cs.allow-unsigned-executable-memory这两个 entitlement。如果你是自己编译的需要在编译后手动签名codesign --force --sign - --entitlements fex.entitlements FEXLoader其中fex.entitlements文件内容如下?xml version1.0 encodingUTF-8? !DOCTYPE plist PUBLIC -//Apple//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd plist version1.0 dict keycom.apple.security.cs.allow-jit/key true/ keycom.apple.security.cs.allow-unsigned-executable-memory/key true/ /dict /plist没有这个签名FEX-Emu 启动时会直接崩溃报错信息是“无法分配可执行内存”。这个坑我卡了大半天后来在项目的 issue 里才找到答案。3.3 Wine prefix 的创建与 DXMT 的注入Wine 的 prefix 可以理解为一个虚拟的 Windows 环境每个 prefix 有独立的注册表、文件系统和 DLL 配置。我建议为每个游戏单独创建一个 prefix避免 DLL 冲突。创建 prefix 的命令WINEARCHwin64 WINEPREFIX~/wine-madeira wineboot --init这里WINEARCHwin64指定 64 位环境因为 FEX-Emu 主要翻译 x86-64 指令32 位支持相对弱一些。创建完 prefix 后需要把 DXMT 的 DLL 复制到 prefix 的 system32 目录并在 Wine 的 DLL 覆盖设置里把 d3d11、dxgi、d3d10core 等设置为 native。具体操作cp DXMT/bin/*.dll ~/wine-madeira/drive_c/windows/system32/ WINEPREFIX~/wine-madeira wine reg add HKCU\Software\Wine\DllOverrides /v d3d11 /t REG_SZ /d native /f WINEPREFIX~/wine-madeira wine reg add HKCU\Software\Wine\DllOverrides /v dxgi /t REG_SZ /d native /fDXMT 的配置还需要一个dxmt.conf文件放在 prefix 的根目录或者游戏目录下。这个文件控制 Metal 的一些行为比如是否启用 MetalFX 超分、是否强制使用某个 GPU。我一般会加上这几行[DXMT] MetalFXUpscale 1 MaxFrameLatency 1MetalFXUpscale开启后游戏可以以较低分辨率渲染然后通过 MetalFX 超分到原生分辨率对帧数提升很明显。MaxFrameLatency设为 1 可以减少输入延迟但可能会增加 GPU 负载需要根据具体游戏调整。3.4 启动游戏时的环境变量与参数启动游戏时你需要通过 FEX-Emu 来加载 Wine而不是直接运行 Wine。命令大概是这样的FEX_ROOTFS~/fex-rootfs \ FEX_APP_CONFIG~/fex-config \ WINEPREFIX~/wine-madeira \ ~/FEXLoader ~/wine-madeira/drive_c/windows/system32/wine64 game.exe这里FEX_ROOTFS指向 FEX 的 rootfs里面包含了 x86-64 的库文件FEX_APP_CONFIG是 FEX 的配置文件目录。这两个环境变量如果不设置FEX 会使用默认路径但默认路径可能不对导致找不到 x86-64 的 libc 或者其他基础库。另外FEX-Emu 有一些性能相关的环境变量可以调FEX_TSOENABLED1开启 x86 的内存序模拟对多线程游戏是必须的但会损失一些性能FEX_VECTORTSOENABLED0关闭向量内存序模拟可以提升性能但某些游戏可能会出问题FEX_MULTIBLOCK1开启多块 JIT 编译提升翻译效率我一般会先全部开启跑一遍看稳定性如果没问题再逐个关闭来测试性能提升。实测下来FEX_MULTIBLOCK1对帧数提升最明显大概有 10% 到 15% 的提升。4. 乱码、崩溃、性能骤降三类高频问题的排查链路4.1 Wine 乱码问题的根因与修复热搜词里“wine 乱码”“wine 栏是乱码”出现频率很高说明这是很多人的痛点。Wine 乱码通常出现在两个地方一是安装界面或者配置工具的界面文字变成方块或者问号二是游戏内某些文字渲染异常。界面乱码的根因是字体缺失。Wine 默认使用宿主系统的字体但 macOS 的字体路径和 Linux 不同Wine 可能找不到合适的中文字体。解决办法是安装 Windows 核心字体WINEPREFIX~/wine-madeira winetricks corefonts WINEPREFIX~/wine-madeira winetricks cjkfontscorefonts安装 Arial、Times New Roman 等西文字体cjkfonts安装中文字体。如果cjkfonts下载失败winetricks 的字体下载源有时候不稳定你可以手动把 macOS 的字体复制到 Wine 的字体目录cp /System/Library/Fonts/PingFang.ttc ~/wine-madeira/drive_c/windows/Fonts/然后在 Wine 的注册表里把默认字体替换成 PingFangWINEPREFIX~/wine-madeira wine reg add HKCU\Software\Wine\Fonts\Replacements /v MS Shell Dlg /t REG_SZ /d PingFang SC /f WINEPREFIX~/wine-madeira wine reg add HKCU\Software\Wine\Fonts\Replacements /v MS Shell Dlg 2 /t REG_SZ /d PingFang SC /f游戏内文字乱码则可能是编码问题。有些老游戏使用 GBK 编码而 Wine 默认用 UTF-8导致文字显示为乱码。这种情况需要在启动游戏时设置LANG环境变量LANGzh_CN.GBK WINEPREFIX~/wine-madeira wine game.exe但 macOS 的 locale 支持有限zh_CN.GBK可能不存在。更可靠的办法是用LC_ALLzh_CN.UTF-8配合游戏内的编码设置或者使用 Locale Emulator 这类工具来模拟区域设置。4.2 FEX-Emu 崩溃的排查顺序FEX-Emu 崩溃的表现通常是游戏启动后立即退出或者运行到某个场景时闪退。排查时我一般按这个顺序来第一步看 FEX 的日志。设置FEX_LOGLEVELinfo或者FEX_LOGLEVELdebugFEX 会输出详细的翻译日志。如果日志里出现“Unhandled instruction”或者“Invalid memory access”说明遇到了 FEX 不支持的指令或者内存访问越界。第二步检查 TSO 设置。如果游戏是多线程的FEX_TSOENABLED0可能导致数据竞争表现为随机崩溃。把 TSO 打开再试。第三步检查 Wine 的 DLL 覆盖。有些游戏需要特定的 DLL 版本比如 d3dcompiler_47、xaudio2_7 等。用 winetricks 安装对应的组件WINEPREFIX~/wine-madeira winetricks d3dcompiler_47 xaudio2_7第四步检查 DXMT 的兼容性。不是所有 D3D 特性 DXMT 都支持。如果游戏使用了 DXMT 尚未实现的 D3D12 特性可能会崩溃。可以尝试切换到 DXVK MoltenVK 的方案或者用 Wine 自带的 wined3d性能差但兼容性好。4.3 性能骤降的几种典型场景性能骤降比崩溃更让人头疼因为游戏能跑但帧数突然从 30 掉到 5。我遇到过几种典型场景场景一进入新区域时帧数暴跌。这通常是着色器编译导致的。DXMT 在第一次遇到某个着色器时需要编译成 Metal 着色器编译过程是同步的会阻塞渲染。解决办法是开启 DXMT 的着色器缓存或者使用MetalShaderCache选项。有些游戏支持预编译着色器可以在游戏设置里开启。场景二大量粒子效果时帧数暴跌。这通常是指令翻译的开销。粒子效果涉及大量浮点运算和 SIMD 指令FEX-Emu 翻译这些指令时开销较大。可以尝试开启FEX_VECTORTSOENABLED0来减少内存序模拟的开销但要注意可能引入渲染错误。场景三切换场景时卡顿。这通常是 I/O 问题。Wine 的文件系统翻译层在处理大量小文件读写时效率不高。可以把游戏安装到 APFS 格式的 SSD 上并且关闭 macOS 的 Spotlight 索引sudo mdutil -i off /Volumes/YourGameDrive另外Wine 的WINEDEBUG环境变量如果设成了all会产生大量日志输出严重拖慢性能。确保WINEDEBUG是-all或者空值。5. iOS 上跑 Windows 程序的现实与幻想5.1 iOS 的限制到底卡在哪里热搜词里有“ios游戏”“ios开发者模式”“ios自动化”“ios 无感”“ios 无感漏洞”这些说明很多人想在 iOS 上跑 Windows 程序或者游戏。但 iOS 的限制比 macOS 严格得多核心卡点有三个第一JIT 权限。iOS 默认不允许应用分配可执行内存这意味着 FEX-Emu 这种动态翻译器无法工作。除非应用有com.apple.security.cs.allow-jitentitlement而这个 entitlement 只对系统应用或者通过特殊途径安装的应用开放。普通 App Store 应用拿不到这个权限。第二后台限制。iOS 对后台进程的限制很严格一个翻译层应用如果切到后台很快就会被挂起。这对于需要持续运行的游戏来说是不可接受的。第三输入和显示。iOS 的触摸输入和 Windows 的鼠标键盘输入差异很大Wine 需要做大量适配。显示方面iOS 的 Metal 虽然和 macOS 同源但某些特性比如 MetalFX在 iOS 上的可用性不同。所以如果你看到有人在 iOS 上跑 Windows 游戏大概率是以下几种情况之一一是使用了越狱设备绕过了 JIT 限制二是使用了远程串流方案游戏实际运行在另一台机器上三是使用了云游戏服务iOS 设备只是显示终端。5.2 开发者模式下的有限可能性iOS 的开发者模式确实开放了一些额外权限比如允许调试器附加、允许安装自签名应用。但开发者模式并不开放 JIT 权限。你可以在开发者模式下安装一个包含 FEX-Emu 的应用但 FEX-Emu 启动时会因为无法分配可执行内存而失败。有一种折中方案是 AOT 预编译在 macOS 上先把 x86-64 代码翻译成 ARM64 代码然后把翻译后的代码打包进 iOS 应用。这样就不需要运行时 JIT 了。但 AOT 翻译的缺点是灵活性差无法处理自修改代码或者动态生成的代码很多游戏和应用的兼容性会大打折扣。5.3 如果你只是想在 iOS 上玩 Windows 老游戏如果你的目标只是玩一些老游戏比如《植物大战僵尸》《三国志》之类的我建议考虑以下替代方案ScummVM支持大量经典冒险游戏有 iOS 版本DOSBox有 iOS 版本可以跑 DOS 游戏RetroArch支持多种模拟器核心有 iOS 版本远程串流在 Mac 或 PC 上运行游戏用 Moonlight 或者 Steam Link 串流到 iOS 设备这些方案的体验比硬上 Wine FEX-Emu 要好得多而且不需要折腾开发者模式或者签名。6. 几个容易被忽略的配置细节与个人经验6.1 Metal 着色器缓存的位置与清理DXMT 编译的 Metal 着色器会缓存在~/Library/Caches/DXMT或者 prefix 目录下的dxmt_cache文件夹。这个缓存有时候会损坏导致游戏渲染异常。如果你遇到画面闪烁、纹理错误可以尝试删除缓存目录让 DXMT 重新编译rm -rf ~/Library/Caches/DXMT rm -rf ~/wine-madeira/drive_c/dxmt_cache但要注意删除缓存后第一次进入游戏会非常慢因为所有着色器都要重新编译。所以除非确实遇到渲染问题否则不要随便删缓存。6.2 Wine 的 Windows 版本设置Wine 默认模拟的 Windows 版本可能比较老有些新游戏会检测 Windows 版本并拒绝运行。你可以用winecfg把 Windows 版本设置为 Windows 10 或者 Windows 11WINEPREFIX~/wine-madeira winecfg在“应用程序”标签页里把 Windows 版本改为 Windows 10。但要注意有些老游戏在 Windows 10 模式下反而会出问题所以最好为每个游戏单独设置。6.3 输入法的冲突问题在 macOS 上使用 Wine 时macOS 的输入法可能会和 Wine 的输入处理冲突表现为按键无响应或者输入重复字符。我一般的做法是在游戏运行时切换到英文输入法或者用WINEDLLOVERRIDES禁用 Wine 的输入法相关 DLLWINEDLLOVERRIDESmsctfb WINEPREFIX~/wine-madeira wine game.exemsctfb表示禁用 msctf.dll这个 DLL 负责文本服务框架禁用后可以避免一些输入法冲突。6.4 音频爆音与延迟Wine 在 macOS 上默认使用 CoreAudio 输出但有时候会出现爆音或者延迟。可以尝试在winecfg的“音频”标签页里把输出设备改为“默认”或者调整采样率。如果游戏支持把音频输出改为 DirectSound 而不是 WinMM 也可能改善。另外FEX-Emu 的指令翻译可能会影响音频线程的实时性导致音频卡顿。可以尝试提高音频线程的优先级或者使用FEX_SINGLETHREAD1来减少线程切换开销但会降低多核利用率。6.5 备份你的 prefixWine prefix 一旦配置好建议整个目录打包备份。因为重新配置一个能跑特定游戏的 prefix 可能需要几个小时而恢复备份只需要几分钟。我一般用 tar 打包tar -czvf wine-madeira-backup.tar.gz ~/wine-madeira恢复时直接解压到原路径即可。注意备份前先关闭所有 Wine 进程避免文件状态不一致。7. 这套方案适合谁不适合谁折腾完这一整套东西我的感受是Wine FEX-Emu DXMT 这套方案目前最适合的是喜欢折腾的技术爱好者以及有一些特定老游戏需求、愿意花时间调优的用户。它的优势是开源、免费、可定制你可以深入每一层去调整参数、打补丁、优化性能。但它的劣势也很明显配置复杂、兼容性参差不齐、性能损耗大、出问题排查困难。如果你只是想安安静静玩个游戏不想折腾命令行和配置文件那 CrossOver 或者买一台 Windows 掌机可能是更省心的选择。如果你对技术原理感兴趣想搞清楚 x86-64 到 ARM64 的翻译到底是怎么工作的那这套方案是一个非常好的学习平台。你可以从 FEX-Emu 的日志里看到每一条指令是怎么被翻译的可以从 DXMT 的源码里看到 D3D 调用是怎么映射到 Metal 的这种透明度是商业方案给不了的。最后分享一个小技巧如果你在 FEX-Emu 的日志里看到大量重复的“Block cache miss”说明 JIT 缓存没有生效可能是FEX_APP_CONFIG路径设置不对或者缓存目录没有写权限。检查一下~/.cache/fex-emu目录的权限确保当前用户可读写。这个细节官方文档里没写但实际使用中很关键。
返回列表