- PVSM.RU - https://www.pvsm.ru -
Я с конца сентября запускал 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 [1] запускает Windows‑программы под x64 прямо на iPhone. Внутри три слоя:
FEX‑Emu переводит x86-64 в ARM64 на лету (JIT);
Wine даёт игре привычный Windows API;
DXMT превращает вызовы Direct3D 11 в Metal.
Для JIT на неджейлбрейкнутом телефоне я пользуюсь StikDebug [2]: встроенный помощник Madeira требует отдельный App ID, и скрипт подписи его убирает.
Сам проект сильный, но «просто поставить и запустить» с тяжёлой игрой не выходит. Нужно знать, с какими правами переподписывать приложение, какие из десятков ключей конфига реально что‑то меняют и как по логу понять, чем именно всё упало. Вот эти неписаные знания я и записал, а скучное автоматизировал.
Работал я с 27 сентября по 19 октября 2026-го. Каждый шаг был одинаков: один запуск, один лог, одно изменение. Лог разбирает небольшой скрипт tools/analyze-log.py: что Madeira реально приняла из окружения, в каком порядке загрузились модули, какие были исключения с регистрами, поднялись ли графика, окно и звук, чем всё закончилось.
Полная таблица с причинами лежит в docs/bugs‑and‑fixes.md [3]. Здесь расскажу про те, что запомнились.
Падение при старте, c0000018. У exe фиксированная база ниже 64 МБ, а ему нужно окно по адресу 0x140000000, и оно не выдавалось. Это уже было исправлено в апстриме (Madeira #111), мне осталось его подтянуть.
Падение после первых записей в код. Игра защищена слоем, который переписывает собственный код во время работы, и на этом всё падало. Причиной оказалась утечка в Wine: на пути возврата [exec-req] в ntdll для ARM64EC не вызывался leave_syscall_callback(), и флаг «мы внутри системного вызова» оставался взведённым. Исправление в одну строку, wine #18 [4], принято.
Падение в steamclient64, c0000005. Тут интереснее. Клиент Steam сужает HMODULE до 32 бит, а на iOS нельзя отобразить память ниже границы в 4 ГБ, поэтому модуль живёт по высокому адресу и после усечения указатель никуда не ведёт. Я сделал так, чтобы образу с «суженной» базой выдавалось низкое имя, а VirtualQuery сообщала свободной только ту память, которую реально можно занять. Это Madeira #385 [5], он пока открыт. Из‑за этого моя сборка для телефона — это апстрим плюс один ещё не принятый коммит, без которого DSR падает на старте.
Падение при поиске папки настроек. В Wine‑профиле C:users<user> просто не было AppData. Папки создаются скриптом (device.py profile fix), его же вызывает apply-config.sh [6].
Это заняло больше всего времени, потому что симптомы были разные, а виноваты были три независимых места.
Игра геймпад не видит. В папке игры лежит собственный xinput1_3.dll, и загрузчик брал его вместо встроенного. Правка: загрузчик предпочитает встроенный XInput (wine #19 [7], принят).
Игра геймпад видит, но игнорирует. Окно игры не было активным, а на iOS его активировать просто некому. Теперь win32u делает главное окно процесса активным, пока оно опрашивает XInput (Madeira #149 [8], принят).
Касание мимо экранной кнопки превращалось в клик мышью. Теперь пока показана раскладка геймпада, такие касания мышью не считаются (Madeira #150 [9], принят).
Помогли две вещи: адреса возврата в диагностике и логирование цепочки нажатий клавиш. По ним и нашёлся разрыв. Такие диагностические патчи я теперь держу под рукой.
Это был собственный сторож эмулятора. Он считал обработанные записи самомодифицирующегося кода накопительно, а в меню настроек игра переписывает код каждый кадр, по семь клавиш по кругу. До порога в 2000 дело доходило как раз за полминуты, и процесс убивался. Теперь считаются только подряд идущие одинаковые сбои на потоке (Madeira #148 [10], принят).
После этих правок меня указали в Settings › Credits самой Madeira: «Controller fixes … and a crash‑guard fix».
Из этой серии я вынес одно правило: проверяй, что реально загружено, а не что написано в конфиге. Размер образа и базовый адрес в логе врут реже, чем файл настроек. И второе: чистая сборка на CI лучше «сборки из того, что было». Одна моя сборка, собранная из смеси старых и новых частей, падала в signal_set_full_context, а чистая с CI — нет.
DS3 тяжелее. Steam в нём ставится изнутри Madeira (Madeira Dock) со своим аккаунтом. На заставках 60 FPS, в бою на дефолтных настройках 17–20.
Дальше началась работа с измерениями. Я разбирал логи по фазам: FPS, загрузка GPU, частоты ядер, число draw‑вызовов на кадр. Парсеры лежат в tools/ds3perf/, а выводы с пометками «факт» и «версия» — в docs/perf/ [11], там 22 заметки на русском.
Самая неприятная находка из DS3-POWER.md. В одной из длинных сессий на первых секундах игры P‑ядра работали на 2,8 ГГц и давали около 34 FPS. Примерно на 59-й секунде включился зажим: частота ушла к 1,8 ГГц, а медиана FPS упала до 20,6. На 175-й секунде iOS объявила термальное состояние serious, и это уже ничего не поменяло. Так что любая оптимизация меряется только на горячем телефоне, иначе цифры красивые и бесполезные.
Пакеты изменений я называл по буквам. Таблица из docs/compatibility.md [12], медиана в тяжёлых сценах:
|
Шаг |
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 [13], #43 [14]).
Два отдельных бага DXMT, оба описаны в DS3-CRASH.md и DS3-FREEZE.md.
Чёрный экран: на запрос описания SRV для «всех мип‑уровней» DXMT отдавал MipLevels = -1. Игра берёт это число как количество уровней и выделяет по нему массив, после чего падает. Теперь возвращается разрешённое значение (dxmt #40 [15]).
Зависание DS3: бэкпорт исправления из 3Shain/dxmt, где циклы маршалинга аргументов отрисовки для GS/TS не продвигались (dxmt #41 [16]).
Геймпад и сохранения в DS3 я полноценно не проверял, в репозитории это написано в разделе «не тестировалось».
Репозиторий madeira‑kit [17] — это обвязка вокруг цикла «сборка, подпись, установка, настройка, запуск, чтение лога, одно изменение». Тут нет форка Madeira: фиксы я отправлял апстриму, а в patches/ лежат только справочные копии.
unpack.sh [18], swap-dll.sh [19], sign.sh [20], install.sh [21]: распаковать сборку, подложить патченые DLL, переподписать своим сертификатом, поставить с сохранением данных приложения;
doctor.sh [22]: проверка перед запуском (телефон виден, приложение стоит, свободно не меньше 3 ГБ, копия игры на месте);
apply-config.sh [6]: загрузить madeira.cfg, прочитать обратно и сравнить, создать недостающие папки профиля;
pull-log.sh [23] и 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 [24]: 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 [25], лицензия MIT для скриптов и документов, патчи следуют лицензиям проектов, к которым они написаны. Issues и PR открыты. Заметки и новые сборки выкладываю в канале t.me/meshoklv [26]. Если статья показалась полезной, звезда на репозитории поможет другим его найти.
Mike Meshok
Автор: meshoklv
Источник [27]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/ios/460715
Ссылки в тексте:
[1] Madeira: https://github.com/willfaust/Madeira
[2] StikDebug: https://github.com/StikDebug/StikDebug
[3] docs/bugs‑and‑fixes.md: https://github.com/meshoklv/madeira-kit/blob/main/docs/bugs-and-fixes.md
[4] wine #18: https://github.com/willfaust/wine/pull/18
[5] Madeira #385: https://github.com/willfaust/Madeira/pull/385
[6] apply-config.sh: http://apply-config.sh
[7] wine #19: https://github.com/willfaust/wine/pull/19
[8] Madeira #149: https://github.com/willfaust/Madeira/pull/149
[9] Madeira #150: https://github.com/willfaust/Madeira/pull/150
[10] Madeira #148: https://github.com/willfaust/Madeira/pull/148
[11] docs/perf/: https://github.com/meshoklv/madeira-kit/tree/main/docs/perf
[12] docs/compatibility.md: https://github.com/meshoklv/madeira-kit/blob/main/docs/compatibility.md
[13] dxmt #42: https://github.com/willfaust/dxmt/pull/42
[14] #43: https://github.com/willfaust/dxmt/pull/43
[15] dxmt #40: https://github.com/willfaust/dxmt/pull/40
[16] dxmt #41: https://github.com/willfaust/dxmt/pull/41
[17] madeira‑kit: https://github.com/meshoklv/madeira-kit
[18] unpack.sh: http://unpack.sh
[19] swap-dll.sh: http://swap-dll.sh
[20] sign.sh: http://sign.sh
[21] install.sh: http://install.sh
[22] doctor.sh: http://doctor.sh
[23] pull-log.sh: http://pull-log.sh
[24] docs/guide.md: https://github.com/meshoklv/madeira-kit/blob/main/docs/guide.md
[25] github.com/meshoklv/madeira‑kit: http://github.com/meshoklv/madeira-kit
[26] t.me/meshoklv: http://t.me/meshoklv
[27] Источник: https://habr.com/ru/articles/1098608/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1098608
Нажмите здесь для печати.