Я с конца сентября запускал PC‑версии Dark Souls на iPhone Air через эмулятор Madeira. Remastered теперь играется с экранным геймпадом, у Dark Souls III в тяжёлых сценах медиана выросла с примерно 20 до 36,7 FPS на экспериментальной сборке. По дороге набралось 5 принятых и 11 открытых PR в Madeira, Wine, FEX и DXMT и репозиторий со скриптами, который я теперь выкладываю.

Оговорка сразу: у меня один телефон (iPhone Air на бета‑версии iOS 27.2), один тестер, то есть я, и все цифры ниже снимались на этом устройстве. Игры у меня свои, купленные. В репозитории нет ни игровых файлов, ни сейв‑редакторов, ни обхода защиты, и принимать такое я не буду.

Что это за зверь

Madeira запускает Windows‑программы под x64 прямо на iPhone. Внутри три слоя:

  • FEX‑Emu переводит x86-64 в ARM64 на лету (JIT);

  • Wine даёт игре привычный Windows API;

  • DXMT превращает вызовы Direct3D 11 в Metal.

Для JIT на неджейлбрейкнутом телефоне я пользуюсь StikDebug: встроенный помощник Madeira требует отдельный App ID, и скрипт подписи его убирает.

Сам проект сильный, но «просто поставить и запустить» с тяжёлой игрой не выходит. Нужно знать, с какими правами переподписывать приложение, какие из десятков ключей конфига реально что‑то меняют и как по логу понять, чем именно всё упало. Вот эти неписаные знания я и записал, а скучное автоматизировал.

Dark Souls Remastered: восемь граблей подряд

Работал я с 27 сентября по 19 октября 2026-го. Каждый шаг был одинаков: один запуск, один лог, одно изменение. Лог разбирает небольшой скрипт tools/analyze-log.py: что Madeira реально приняла из окружения, в каком порядке загрузились модули, какие были исключения с регистрами, поднялись ли графика, окно и звук, чем всё закончилось.

Полная таблица с причинами лежит в docs/bugs‑and‑fixes.md. Здесь расскажу про те, что запомнились.

Падение при старте, c0000018. У exe фиксированная база ниже 64 МБ, а ему нужно окно по адресу 0x140000000, и оно не выдавалось. Это уже было исправлено в апстриме (Madeira #111), мне осталось его подтянуть.

Падение после первых записей в код. Игра защищена слоем, который переписывает собственный код во время работы, и на этом всё падало. Причиной оказалась утечка в Wine: на пути возврата [exec-req] в ntdll для ARM64EC не вызывался leave_syscall_callback(), и флаг «мы внутри системного вызова» оставался взведённым. Исправление в одну строку, wine #18, принято.

Падение в steamclient64, c0000005. Тут интереснее. Клиент Steam сужает HMODULE до 32 бит, а на iOS нельзя отобразить память ниже границы в 4 ГБ, поэтому модуль живёт по высокому адресу и после усечения указатель никуда не ведёт. Я сделал так, чтобы образу с «суженной» базой выдавалось низкое имя, а VirtualQuery сообщала свободной только ту память, которую реально можно занять. Это Madeira #385, он пока открыт. Из‑за этого моя сборка для телефона — это апстрим плюс один ещё не принятый коммит, без которого DSR падает на старте.

Падение при поиске папки настроек. В Wine‑профиле C:\users\<user> просто не было AppData. Папки создаются скриптом (device.py profile fix), его же вызывает apply-config.sh.

Геймпад: три бага в одной цепочке

Это заняло больше всего времени, потому что симптомы были разные, а виноваты были три независимых места.

  1. Игра геймпад не видит. В папке игры лежит собственный xinput1_3.dll, и загрузчик брал его вместо встроенного. Правка: загрузчик предпочитает встроенный XInput (wine #19, принят).

  2. Игра геймпад видит, но игнорирует. Окно игры не было активным, а на iOS его активировать просто некому. Теперь win32u делает главное окно процесса активным, пока оно опрашивает XInput (Madeira #149, принят).

  3. Касание мимо экранной кнопки превращалось в клик мышью. Теперь пока показана раскладка геймпада, такие касания мышью не считаются (Madeira #150, принят).

Помогли две вещи: адреса возврата в диагностике и логирование цепочки нажатий клавиш. По ним и нашёлся разрыв. Такие диагностические патчи я теперь держу под рукой.

Вылет через 35 секунд в меню настроек

Это был собственный сторож эмулятора. Он считал обработанные записи самомодифицирующегося кода накопительно, а в меню настроек игра переписывает код каждый кадр, по семь клавиш по кругу. До порога в 2000 дело доходило как раз за полминуты, и процесс убивался. Теперь считаются только подряд идущие одинаковые сбои на потоке (Madeira #148, принят).

После этих правок меня указали в Settings › Credits самой Madeira: «Controller fixes … and a crash‑guard fix».

Из этой серии я вынес одно правило: проверяй, что реально загружено, а не что написано в конфиге. Размер образа и базовый адрес в логе врут реже, чем файл настроек. И второе: чистая сборка на CI лучше «сборки из того, что было». Одна моя сборка, собранная из смеси старых и новых частей, падала в signal_set_full_context, а чистая с CI — нет.

Dark Souls III: от 20 до 36,7 FPS

DS3 тяжелее. Steam в нём ставится изнутри Madeira (Madeira Dock) со своим аккаунтом. На заставках 60 FPS, в бою на дефолтных настройках 17–20.

Дальше началась работа с измерениями. Я разбирал логи по фазам: FPS, загрузка GPU, частоты ядер, число draw‑вызовов на кадр. Парсеры лежат в tools/ds3perf/, а выводы с пометками «факт» и «версия» — в docs/perf/, там 22 заметки на русском.

Телефон нагревается и режет частоты

Самая неприятная находка из DS3-POWER.md. В одной из длинных сессий на первых секундах игры P‑ядра работали на 2,8 ГГц и давали около 34 FPS. Примерно на 59-й секунде включился зажим: частота ушла к 1,8 ГГц, а медиана FPS упала до 20,6. На 175-й секунде iOS объявила термальное состояние serious, и это уже ничего не поменяло. Так что любая оптимизация меряется только на горячем телефоне, иначе цифры красивые и бесполезные.

Что сработало

Пакеты изменений я называл по буквам. Таблица из docs/compatibility.md, медиана в тяжёлых сценах:

Шаг

FPS

Что поменялось

базовый набор C2

~17-20

разделение пулов, без копирования образа, «осиротевшие» блокировки помечаются

G1

21,5

облегчённая диагностика, синхронизация внутри процесса, быстрый путь критических секций для x64, окна записи для «горячих» страниц кода

H2

36,7

повторное использование буферов и списков команд в DXMT, быстрый TLS, облегчённые SRW‑блокировки, QoS потоков по имени

Для H2 в тяжёлых сценах: медиана 36,7 FPS, p10 28,8 в первые минуты 12-минутного прогона. После прогрева, когда P‑ядра сидят на 1,31 ГГц, держится 32–34 FPS. GPU при этом занят примерно на 88%, то есть упираемся теперь в него, а не в процессор.

Теперь честная часть. Цифра 36,7 — это сумма нескольких изменений. Вклад каждого по отдельности я не мерил, и в каждом PR это написано прямо. На G1 был прогон на 26 минут без зависаний с медианой 21,5.

Что я проверил и отбросил:

  • MetalFX: стало хуже;

  • pool-low: стало хуже;

  • пропуск записей самомодифицирующегося кода с теми же байтами: бессмысленно, потому что 93% записей байты меняют.

Отдельно про DXMT. Оказалось, что он создаёт около тысячи Metal‑буферов на кадр и примерно 50 раз за кадр выделяет и освобождает по 2 МБ под списки команд. Два ключа (DXMT_DYN_KEEP и DXMT_CMDLIST_KEEP_BLOCK) убирают эту суету, оба выключены по умолчанию (dxmt #42, #43).

Чёрный экран и зависание в DS3

Два отдельных бага DXMT, оба описаны в DS3-CRASH.md и DS3-FREEZE.md.

  • Чёрный экран: на запрос описания SRV для «всех мип‑уровней» DXMT отдавал MipLevels = -1. Игра берёт это число как количество уровней и выделяет по нему массив, после чего падает. Теперь возвращается разрешённое значение (dxmt #40).

  • Зависание DS3: бэкпорт исправления из 3Shain/dxmt, где циклы маршалинга аргументов отрисовки для GS/TS не продвигались (dxmt #41).

Геймпад и сохранения в DS3 я полноценно не проверял, в репозитории это написано в разделе «не тестировалось».

Что в репозитории

Репозиторий madeira‑kit — это обвязка вокруг цикла «сборка, подпись, установка, настройка, запуск, чтение лога, одно изменение». Тут нет форка Madeira: фиксы я отправлял апстриму, а в patches/ лежат только справочные копии.

  • unpack.sh, swap-dll.sh, sign.sh, install.sh: распаковать сборку, подложить патченые DLL, переподписать своим сертификатом, поставить с сохранением данных приложения;

  • doctor.sh: проверка перед запуском (телефон виден, приложение стоит, свободно не меньше 3 ГБ, копия игры на месте);

  • apply-config.sh: загрузить madeira.cfg, прочитать обратно и сравнить, создать недостающие папки профиля;

  • pull-log.sh и analyze-log.py: забрать лог и сразу разобрать;

  • готовые профили для DS1 и DS3 в configs/.

Минимальный путь выглядит так:

git clone https://github.com/meshoklv/madeira-kit && cd madeira-kit
cp scripts/config.example.env scripts/config.env && $EDITOR scripts/config.env
scripts/unpack.sh ~/Downloads/Madeira-build.zip && scripts/sign.sh && scripts/install.sh

scripts/doctor.sh
scripts/apply-config.sh configs/ds1-play.cfg
# смахнуть Madeira, включить JIT в StikDebug, запустить игру
scripts/pull-log.sh first-run

Понадобятся Mac с Xcode command line tools, iPhone по USB, сертификат и профиль для вашего bundle id и pip3 install pymobiledevice3. Entitlements на расширенную память и расширенное виртуальное адресное пространство требуют платного аккаунта разработчика.

Если собираете Madeira на GitHub Actions сами, грабли описаны в docs/guide.md: LLVM только статическими библиотеками, TUNE_CPU=cortex-a78 для FEX, заглушка для ri_page_wait_time_mach. Windows‑часть DXMT этот CI не пересобирает.

Чего я не знаю

  • Скрипты в репозитории — мой рабочий конвейер, из которого я убрал личные идентификаторы. После этого я проверил синтаксис, но целиком на устройстве их не перепрогонял.

  • Другие модели iPhone и версии iOS не проверялись, как и свежий клон репозитория на второй машине.

  • FPS и нагрев в самой Dark Souls Remastered я не замерял, только «играется».

  • Все цифры по DS3 — один телефон и считанные прогоны, чаще один прогон на конфигурацию.

  • Бесплатный аккаунт разработчика может не дать нужных прав.

Как помочь

Если у вас другой iPhone или iPad, пришлите отчёт о совместимости: модель, версия iOS, игра, конфиг и результат. Принимаются профили с измеренными цифрами. Не принимаются кряки, файлы игр и всё, что обходит защиту.

Часть кода и патчей я писал вместе с ИИ‑ассистентом (Claude) — в коммитах апстрим‑PR это видно по строке Co-Authored-By.

Репозиторий: github.com/meshoklv/madeira‑kit, лицензия MIT для скриптов и документов, патчи следуют лицензиям проектов, к которым они написаны. Issues и PR открыты. Заметки и новые сборки выкладываю в канале t.me/meshoklv. Если статья показалась полезной, звезда на репозитории поможет другим его найти.

Mike Meshok