[Перевод] Улучшения в эмуляторе Dolphin
Многие сообщества геймеров благодарны разработчикам эмуляторов за их многолетний труд. Эмуляторы — важная часть многих сообществ любителей классических игр, они предоставляют игрокам доступ к таким функциям, как сетевой мультиплеер, моддинг, сохранения, а также открывают усовершенствования, невозможные на консоли. Если вам захочется поиграть в любимую игру, иногда просто удобнее воспользоваться эмулятором на десктопном компьютере, планшете или телефоне, чем откапывать и подключать консоль. Однако важно заметить, что наши отношения с игровыми сообществами взаимны и без помощи игроков и фанатов мы бы не смогли поддерживать библиотеку из тысяч игр.
Основным катализатором многих изменений, описанных в этом отчёте, стали сообщества игроков. Они занимались сложной отладкой, находили мелкие проблемы, которые оставались бы незаметными для тех, кто не знает игру в совершенстве, и даже создавали патчи, чтобы игры лучше подстраивались под усовершенствования в эмуляторе. Весь этот вклад, хотя и не являлся кодом, очень ценим нами, благодаря нему Dolphin стал тем, что мы видим сегодня.
Значимые изменения
5.0–14795 — JIT: Fix FMA Negation Ordering, JosJuice
Inazuma Eleven GO: Strikers 2013 — последний релиз для Wii любимой игроками футбольной серии Inazuma Eleven. Эту игру можно любить за многое — множество персонажей, специальные движения, длинный режим RPG-истории, в которой вы собираете собственную футбольную команду, прокачиваете персонажей и побеждаете противников. Несмотря на то, что игра была выпущена только в Японии, она стала культовой для игроков всего мира. Существуют её фанатские переводы, по ней проводятся турниры между странами и даже есть «Кубок мира»!
В этом году уже прошло несколько турниров и онлайн-соревнований!
Хотя в Wiimmfi уже есть полная поддержка игры, в Inazuma Eleven GO: Strikers 2013 по-прежнему играют онлайн через Nintendo Wi-Fi Connection, и многие пользователи выбирают Dolphin. Это одна из немногих игр Wii, для которых до сих пор можно найти матчи, особенно если зайти на один из Discord-серверов сообщества. В Dolphin всё работает отлично, за исключением одного раздражающего изъяна: Dolphin не может синхронизироваться с консолями Wii. При попытке выполнить блок Hissatsu (специальные движения) или отбор мяча игра обнаруживает проблему и откатывается к точке до момента её возникновения, обычно сбрасывая мяч в неподвижную позицию. Это означает, что забивать голы мощными специальными движениями невозможно, как и отбирать мяч у противников. Игра была неиграбельной.
В анимации показана неудачная попытка поймать мяч, однако после небольшой загрузки мяч всё равно оказывается в руках вратаря. Причина этого — откат для восстановления из-за рассинхронизации. Видео в высоком качестве можно посмотреть здесь
Одним из поединков в рамках организованного сообществом Кубка мира должна была стать игра Франции и Японии, что создавало проблему. Французское сообщество игроков в основном использует Dolphin, а большинство японских игроков играет только на консоли. Это означало, что игрокам или придётся перейти на непривычную систему, или отменить матч из-за этого бага. Игроки сообществ всех стран решили, что с них хватит: они доберутся до самой сути этой проблемы, чего бы это ни стоило. Ветераны Inazuma, в том числе такие игроки, как Obluda, AS, GalacticPirate и множество других, объединили свои усилия для выявления абсолютно кошмарного бага эмуляции.
Этот баг стал такой проблемой из-за чрезвычайно конкретных условий, которые требовались для его воссоздания. Обычно при исследовании потенциальных багов ЦП приходится выполнять такие действия, как приостановка эмуляции, подключение отладчиков, изучение регистров и другие технические действия, чтобы конкретно изучить происходящее. Вдобавок ко всему этому разработчики часто используют интерпретатор Dolphin для проверки правильности JIT, чтобы определить, с каким типом бага они имеют дело. В прошлом подобные инструменты и тесты оборудования помогли разработчикам найти различия в вычислениях, которые когда-то вызывали рассинхронизацию реплеев в таких играх, как Mario Kart Wii, F-Zero GX, Super Smash Bros. Brawl и многих других.
Inazuma Eleven GO: Strikers 2013 имела похожую проблему, но из-за одного ограничения её было очень сложно изучить. Чтобы баг проявился, эмулятор должен быть подключен к Wi-Fi, соединённому с Wii. Это означало, что Dolphin должен работать почти на полной скорости и его нельзя ставить на паузу на долгий промежуток времени, ведь в противном случае соединение будет утеряно. По сути, это отсекает большинство способов, которые обычно используются для исследования и тестирования связанных с ЦП багов; даже процесс проверки в интерпретаторе того, что проблема возникла, становится нетривиальной задачей. Полный анализ команд обычными средствами тоже было невозможно реализовать, потому что это слишком бы снизило производительность. И хотя все подозревали, что это был баг JIT, мы не могли в этом убедиться, поскольку не было возможности проверить, устраняет ли её переключение на интерпретатор!
Несмотря на эти препятствия, сообщество игроков в Inazuma приложило все свои усилия. Вместо использования традиционного анализа оно начало мучительный путь отката небольших групп команд в интерпретатор. При наличии достаточно быстрого процессора игроки могли запускать игру с полной скоростью и медленно тестировать каждую версию команд в интерпретаторе, чтобы проверить, не устранит ли одна из них проблему. Они достигли успеха, исследуя команды JIT с плавающей запятой. Отключив их группу, они смогли устранить рассинхронизацию, оставаясь почти на полной скорости, чтобы соединение с Wii не разорвалось. Имея на руках эту информацию, в работу включился JosJuice, чтобы помочь пользователям в анализе оставшихся команд, и они нашли причину в командах совмещённого умножения-сложения (Fused Multiply–Add, FMA) с плавающей запятой. Разработчики отнеслись к этому анализу скептически, потому JIT и x86–64, и AArch64 были тщательно проверены. К тому моменту они должны были стать практически идеальными, что подтверждается тестами оборудования и многими играми с файлами реплеев.
К нему присоединились другие пользователи, а один разработчик даже импортировал игру, чтобы проверить, что происходит. Благодаря помощи сообщества Inazuma Eleven GO мы смогли лично убедиться в происходящем и подтвердить анализ команд. Определённо, с вычислениями FMA в Dolphin было что-то не то. Проблема заключалась в том, что никто не мог найти источник, хоть мы и знали, что что-то сломано. После долгого изучения проблемы JosJuice наконец-то разобрался: оказалось, проблема заключалась в различиях в конкретном моменте смены знака. Давайте рассмотрим технические подробности.
Смена знака — это изменение знака с положительного на отрицательный, или наоборот. Для эффективности она объединяется в дублирующие версии команд FMA, например, madd
(умножение-сложение) имеет вариант со сменой знака nmadd
, который должен, теоретически, иметь противоположный madd
знак. Однако различные архитектуры ЦП могут применять смену знака в разные моменты вычислений, что изменяет результат. Команды nmadd
и nmsub
(умножение-вычитание со сменой знака) архитектуры PowerPC выполняют смену знака в конце операции уравнением -(A * C ± B)
. Это логично, поэтому, разумеется, никакая другая архитектура не выполняет операции подобным образом.
x86–64 в своей бесконечной мудрости меняет знак результата операции умножения, а затем выполняет сложение или вычитание. Уравнение имеет вид -(A * C) ± B
, то есть сильно отличается от версии PowerPC и совершенно с ней несовместимо. Однако предыдущие разработчики Dolphin нашли хитрый способ обхода этой проблемы. Для этого достаточно было просто поменять местами ADD и SUB для этих команд. Просто выполняя обратные действия, мы можем получить результаты, которые ожидает код игры для PowerPC.
Но AArch64 всё меняет. Уравнение nmadd
для AArch64 выглядит как -(A * C) - B
, то есть оно полностью идентично уравнению nmsub
на x86–64! То, что команда сложения на самом деле вычитает — это, конечно, любопытное решение со стороны ARM, но благодаря нему нам не нужно выполнять трюк с заменой SUB, потому что AArch64 уже сделала его за нас, позволив сопоставить nmadd
PowerPC напрямую с AArch64, несмотря на очень разные уравнения. Что ещё более странно, уравнение nmsub
на AArch64 выглядит как (A * C) - B
, то есть смена знака в нём вообще не происходит. Однако по какой-то причине знак меняется в msub
AArch64, поэтому мы использовали её. Мы уже научились не задавать лишних вопросов.
Эти трюки очень продуманы и они оказались очень точными. Однако, как доказала игра Inazuma Eleven GO: Strikers 2013, они были неидеальными. Пользователь booto обнаружил, что из-за различий в порядке смены знака в уравнениях, этот способ не срабатывает, когда все входные данные равны нулю — nmsub
PowerPC даёт -0, а nmadd
x86 и msub
AArch64 дают +0. Ой-ёй. Мы не знаем, почему конкретно Inazuma использует это необычное поведение, но это баг, вызывавший рассинхронизацию при совместном подключении к Wi-Fi Connection эмулятора Dolphin и консолей Wii.
Хотя мы устранили эту проблему в Inazuma, дальнейшие исследования выявили другие возможные проблемы. Описанные выше трюки дают одинаковые результаты на консоли, какие бы данные она ни обрабатывала…, но только когда они выполняются обычной математикой. На реальном оборудовании эти уравнения выполняются при помощи математики с плавающей запятой, поэтому снова всплывают давно известные нам погрешности округления операций с плавающей запятой. При смене знака на разных этапах вычисления уравнений, расчёты с плавающей запятой округлялись не так, как в процессорах PowerPC. Обычно это было допустимо, но в пограничных случаях округления, например, при округлении в сторону бесконечности, различия в округлении оказывались достаточно серьёзными, чтобы создать другой результат с плавающей запятой. Не знаю, возникала ли уже в каком-то ПО эта проблема, но по возможности стоит устранять подобные баги.
Чтобы устранить все эти странности, мы теперь просто пользуемся стандартными командами madd
и msub
(и nmsub
на AArch64), после чего самостоятельно меняем их знак отдельными командами смены знака. Это простое изменение разрешает все проблемы пограничных случаев и позволяет эмулятору Dolphin играть против реальных Wii в Inazuma Eleven GO: Strikers 2013! Хотя из-за использования двух команд вместо одной производительность снижается на чрезвычайно малую величину, мы гарантируем, что вы этого не заметите. Вероятно. Ведь не найдётся ни одной игры, которая станет настолько тупо пользоваться простыми командами смены знака FMA, чтобы это вызвало значительное снижение производительности. (Во всяком случае, мы на это надеемся.)
Без потрясающего сообщества игроков в Inazuma, проводившего кошмарный анализ команд со строгим ограничением невозможности слишком большого снижения производительности, эта проблема никогда бы не была устранена. Если вы хотите попробовать сыграть в эту игру, то у неё до сих пор есть активное сообщество, проводятся турниры и существует куча руководств. Мы хотим выразить особую признательность Inazuma France за помощь.
5.0–15009 — IOS/Networking: Make Name Resolution Asynchronous, sepalani
При тестировании онлайна для Inazuma Eleven GO: Strikers 2013, Mario Kart Wii и других игр с поддержкой WiFi на таких резервных серверах, как Wiimmfi, было замечено, что при первоначальном подключении возникают очень серьёзные торможения. Так как из-за проблем Inazuma Eleven с WiFi онлайн-функции и так тестировались, нам представился идеальный шанс протестировать модификацию разработчика sepalani по асинхронному выполнению выбора доменных имён. Благодаря выполнению операции в отдельном потоке торможения при подключении к игре с поддержкой Wi-Fi полностью устранялись.
Ранее подключение было совершенно дёрганным. Видео в более высоком качестве можно посмотреть здесь.
Но теперь оно работает точно так же, как на консоли. Видео в более высоком качестве можно посмотреть здесь.
5.0–14810, 5.0–14848 и 5.0–15105 — GameINI: «Heavy Iron Studios» Games Quality of Life Changes
Ни один из разработчиков лицензионных игр для консолей шестого поколения не оставил наследия лучше, чем Heavy Iron Studios. Одна из игр компании, SpongeBob Squarepants: Battle for Bikini Bottom — культовая классика, получившая HD-ремейк на современных консолях, а среди прочих игр студии есть и крепкие середнячки, и довольно неплохие проекты. В целом, это были увлекательные игры, правильно использовавшие франшизы и сочетающие в себе интересный геймплей с любимыми персонажами.
Так как эти лицензионные игры имеют довольно большую базу фанатов, пользователи хотели играть в них на Dolphin со всеми теми преимуществами, которые даёт эмуляция. К сожалению, возникли ограничения. Dolphin мог корректно эмулировать эти игры…, но самые продвинутые его возможности работали не очень хорошо. При повышении внутреннего разрешения игры возникали серьёзные проблемы с графикой, поэтому игрокам приходилось пользоваться нативным разрешением. Но это не какой-то баг Dolphin! Большинство игр Heavy Iron Studios разрабатывалось таким образом, что в них нельзя было играть в повышенном разрешении из-за использованных при рендеринге трюках (по крайней мере, чтобы решить эту проблему, пользователи и разработчиков эмуляторов должны были придумывать хитрости).
При нативном внутреннем разрешении 1x игра Battle For Bikini Bottom работала нормально…
Но при более высоких внутренних разрешениях возникали серьёзные визуальные ошибки
Истоки этой проблемы можно отследить в первой игре, выпущенной Heavy Iron Studios для GameCube — Scooby Doo: Night of 100 Frights. В ней используются те же техники, что и в Battle for Bikini Bottom, но с одним важным отличием. Эта игра неправильно задаёт матрицу проекции; она настроена на вывод размером 639 на 479 вместо истинного разрешения 640 на 480. Поэтому когда игра копирует из памяти фрагмент буфера кадров размером 256×256, при копировании обратно он пропускается через неправильную матрицу проекции и оказывается слегка деформированным до размера фрагмента 256.401 на 256.534. Проще всего представить этот баг, сравнив его с редактированием фотографии. Представьте, что вы скопировали часть изображения, незначительно уменьшили масштаб всего остального изображения, но при копировании фрагмента обратно вы не изменили его масштаб, а потом отмасштабировали полное изображение до исходного размера. Аналогия неидеальна, но, по крайней мере, может дать вам представление о том, какие визуальные проблемы это может вызвать. Но дело в том, что нативное разрешение GameCube настолько мало, что такие незначительные отклонения не приводили к заметным проблемам. Баг может проявляться визуально только из-за того, что Dolphin позволяет использовать повышенное внутреннее разрешение.
При увеличенных разрешениях возникает незначительный излом в пикселях верхнего левого квадранта…
Однако функция округления вершин (Vertex Rounding) полностью его устраняет.
Ко времени выпуска SpongeBob Squarepants: Battle for Bikini Bottom компания Heavy Iron Studios заметила этот баг и скорректировала поведение. Она не только исправила матрицу проекции, сменив размер на 640×480, но и добавила горизонтальное и вертикальное смещение на 1/512 (полпикселя) к позиции и координатам текстур. Благодаря этому всё действительно выравнивается при повышенных внутренних разрешениях, однако теперь размер текстуры составляет 513/512, а не 1.0. Это означает, что копирование EFB захватывает части самого края экрана. Если мы разобьём на части процесс рендеринга изображения, то увидим, как повышенные разрешения ломают картинку.
Это скриншот того, как выглядит игра примерно на середине процесса рендеринга кадра. Мы видим, что тень ещё не наложена.
При нативном разрешении всё очищается на краю экрана.
При повышенных разрешениях смещения могут вызывать визуальные проблемы.
Пользователи, заметившие эту проблему, прозвали её проблемой «синего бокса», потому что чаще всего она дублировала части скайбокса. Хотя Vertex Rounding может исправить координаты позиций, починив таким образом рендеринг теней, он делает ещё более заметным то, что данные берутся с самого края экрана, потому что координаты текстур по-прежнему смещены.
Без Vertex Rounding тени вполне ожидаемо поломаны, а в левом верхнем углу иногда появляется синий бокс.
Vertex Rounding исправил тени, но проблема с синим боксом стала гораздо более заметной.
Из-за смещения текстур Dolphin никак не мог улучшить рендеринг, если только не применять исключительно неудобные хаки для каждой конкретной игры. Поэтому пользователи решили выбрать другой путь — манипулировать самой игрой, а не пытаться подстроить эмулятор под неё. Для этого они выбрали код Action Replay, позволявший им модифицировать игру непосредственно в памяти. Несколько лет назад люди в отчёте об этой самой проблеме обсуждали идею использования для улучшения ситуации кодов action replay. Они даже опубликовали коды, частично разъяснившие ситуацию, а Disorderly запостил конкретный адрес, который должен оказаться в catalyst для исправления этой игры.
К сожалению, эти решения слишком опередили своё время. Тогда в Dolphin ещё не было хака Vertex Rounding, к тому же в нём присутствовали погрешности округления, из-за которых игра могла некорректно рендериться даже в нативном разрешении. Так как пользователям приходилось одновременно справляться с несколькими проблемами, коды становились чрезмерно сложными и имели множество недостатков. Из-за этого почти никто не понял насколько близко они были тогда к решению.
Такая ситуация сохранялась до этого года, когда разработчикам стало известно решение, позволяющее устранить проблемы с рендерингом игры без багов графики при помощи кода Action Replay из одной строки, появившегося на вики-странице Battle for Bikini Bottom эмулятора Dolphin. Оставалось всего лишь собрать всё вместе. Накопившиеся за годы исправления во внутреннем округлении Dolphin, хак Vertex Rounding и этот код Action Replay наконец-то заставили игру красиво рендериться при высоких разрешениях.
Благодаря этим хитростям Bikini Bottom отлично работает с любым внутренним разрешением!
Однако для этого игрокам приходилось находить код в вики, вводить его в INI эмулятора Dolphin или в меню action replay, включать читы и хак Vertex Rounding, не имея при этом никаких инструкций. Проверив код самостоятельно, JMC47 захотел облегчить жизнь пользователей. Однако вопрос заключался в том, можно ли упростить доступ к повышенному разрешению, не мешая тем, кто хочет наслаждаться игрой в нативном разрешении и без хаков.
При нативном разрешении Vertex Rounding автоматически отключается, поэтому это без проблем можно сделать настройкой по умолчанию. Хотя мы не могли включить по умолчанию код Action Replay, потому что он представляет собой просто запись значения в память, его легко преобразовать в патч для игры. Единственное, в чём нам нужно было убедиться — что этот патч не вызывает проблем в нативном разрешении. Для этого Pokechu22 проанализировал влияние патча при помощи инструмента FifoAnalyzer эмулятора Dolphin. В конечном итоге патч был признан безвредным и преобразован из кода Action Replay в патч игры, который можно автоматически применять при её запуске.
Ради полноты решения JMC47 также модифицировал патч так, чтобы он работал с PAL-версией игры, чтобы вне зависимости от запущенной версии пользователи могли играть в последних тестовых сборках с повышенным разрешением!
Это могло бы стать концом истории, но все пользователи ощущали какую-то горечь. Пусть SpongeBob SquarePants: Battle for Bikini Bottom и является самой популярной игрой Heavy Iron Studios, и её исправление порадовало большинство игроков, другие игры компании всё равно оставались сломанными. Действительно ли эти игры менее важны из-за того, что в них хочет играть меньше людей?
Но был и ещё более важный аспект. Так как эти игры были менее популярны, чем Battle for Bikini Bottom, для них не существовало кода, способного решить проблему со смещениями. Или, по крайней мере, так мы думали. Как ни удивительно, но ещё одна из игр, The SpongeBob SquarePants Movie тоже имела в вики код, помогающий с повышенными разрешениями! Решив, что это не будет большой проблемой, JMC47 решил портировать в патч и этот код. Однако, кое-что мы упустили.
Имевшийся код для The SpongeBob SquarePants Movie удалял большинство эффектов затенения.
Код для The SpongeBob SquarePants Movie не удалял смещение из исполняемого файла, а полностью исключал из рендеринга проблемные копии EFB! Хоть это и устраняло артефакты, при этом терялось и множество спецэффектов игры. Это решение нельзя было использовать как рабочий патч для игры, включенный по умолчанию. Однако эти игры казались настолько похожими, что JMC47 верил в возможность правильного патча. Чтобы создать его, он ещё раз заручился помощью Pokechu22, чтобы изучить рендеринг игры с кодом action replay и без него. Вместе они убедились в том, что этот код был тупиковым путём для устранения источника проблемы. Однако в процессе этого исследования Pokechu22 сообщил, что код для Battle for Bikini Bottom скорее всего более детализирован не из-за популярности игры, а потому, что на её диске содержались отладочные символы в виде неурезанного исполняемого файла ELF. Отладочные символы чрезвычайно полезны для реверс-инжиниринга, поскольку они разбивают программу на функции и назначают им названия непосредственно в коде. Это сильно упрощает понимание их работы.
Разработчики оставили отладочные символы в предыдущей игре, но могли ли они оставить их снова в сиквеле…?
Джекпот!
Оказалось, что на дисках всех игр Heavy Iron Studios той эпохи присутствовал неурезанный файл ELF. Благодаря этому мучительный проект по реверс-инжинирингу превратился в задачу, с которой при достаточном количестве времени и труда справится даже новичок. Благодаря руководству Pokechu22 пользователь JMC47 научился работать с инструментом для реверс-инжиниринга Ghidra, а также с плагинами, разработанными специально для анализа исполняемых файлов GameCube и Wii. Процесс был медленным, но помощь Pokechu22 позволила с ним справиться. На этот раз смещение было не таким, как в Battle for Bikini Bottom; копирование EFB теперь выполнялось в половинном разрешении, но во всём остальном процесс рендеринга не отличался от предыдущей игры. Pokechu22 смог определить значение, находившееся в памяти, после чего JMC47 начал патчить каждое вхождение числа с плавающей запятой, пока не нашёл адрес памяти, исправлявший рендеринг. Сделав это, он создал новый Fifolog для Pokechu22, чтобы тот убедился в работе патча и портировал код на другие регионы игры.
Даже Патрик удивлён тому, что все баги пропали
… Но и на этом история не заканчивается. SpongeBob Squarepants: Battle for Bikini Bottom и The SpongeBob SquarePants Movie были самыми популярными играми с этой проблемой, но Heavy Iron Studios использовала ту же технику в большинстве своих игр. Благодаря работе над The SpongeBob SquarePants Movie JMC47 знал точную последовательность действий для поиска смещённых копий EFB и устранению проблемы. Хотя больше ни одна игра компании для GameCube не была и близко столь же популярна, только лень могла помешать заставить патч работать для всех игр, в которых известна эта проблема. На этот раз кодов, которые можно взять за основу, не было, но на теперь они уже и не требовались.
За следующие несколько недель он собрал все известные игры и версии с этой проблемой, проверил их и разработал патчи для каждой. Поэтому теперь игры наподобие The Incredibles, The Incredibles: Rise of the Underminer и даже различные сборки 2 in 1 SpongeBob/Incredibles имели патчи, обеспечивавшие правильную работу в высоких разрешениях.
Из-за сломанных теней игру приходилось запускать в нативном разрешении.
Но теперь можно играть почти в любую из старых игр Heavy Iron Studios с повышенным разрешением!
И теперь все эти игры работают в повышенном разрешении, но не благодаря каким-то улучшениям в эмуляции, а из-за модификации игры, позволяющей удобнее выполнять рендеринг. Хотя обычно Dolphin по умолчанию не использует включенные патчи или улучшения, мы понимаем, что многие наши пользователи рады возможности запуска игр в высоком разрешении. В данном случае мы не можем особо улучшить эмуляцию игры, но изменив саму игру, мы улучшили рендеринг в высоких разрешениях. И стоит помнить о том, что включение патчей не ухудшает рендеринг игры в нативном разрешении. Поэтому в последних тестовых сборках мы по умолчанию включили и эти патчи, и Vertex Rounding.
Также в последних тестовых сборках мы по умолчанию отключили Dual Core для этих игр после того, как JoeyBallentine и сообщество спидраннеров SpongeBob Squarepants: Battle for Bikini Bottom сообщили нам о проблемах со стабильностью игры. Так как эти игры нетребовательны и им не нужны многие вычислительно затратные функции, это не должно стать проблемой для большинства десктопов и мощных устройствах Android. Но если вас устраивают возникающие время от времени сбои, то вы можете снова включить Dual Core для неё на странице свойств игры.
В течение нескольких лет мы знали, что многие игроки разочарованы количеством проблем Dolphin с играми Heavy Iron Studios. Теперь у них появился отличный шанс пройти эти классические игры заново. Мы думаем, им понравится то, что они увидят.
5.0–14812 — Convert NaN to 1 When Generating Texture Coordinates, Pokechu22
Когда ни донимают его просьбами о помощи в реверс-инжиниринге других игр, Pokechu22 углубляется в исследование самых странных графических багов, возникающих в Dolphin. Его внимание привлекла одна проблема в issue tracker, потому что не было никаких зацепок для её решения. Shadow the Hedgehog — игра, любимая абсолютно всеми фанатами Соника, имела проблемы с рендерингом век глаз персонажей, особенно в некоторых катсценах. К счастью, тестер сохранил Fifolog этого бага, поэтому Pokechu22 проанализировал Fifolog и выяснил, что веки имеют координату текстур NaN (Not a Number). Так как это казалось ужасной ошибкой, он решил воспроизвести Fifolog при помощи Hardware Fifoplayer, и нашёл нечто очень любопытное.
Вот как рендерится Fifolog в Dolphin.
Но на консоли Fifolog рендерится корректно, то есть на ней существует какая-то специальная обработка NaN!
Походило на то, что реальное «железо» каким-то образом автоматически исправляет NaN. Pokechu22 продолжил разбираться с проблемой на консоли, в конечном итоге поняв, что консоль интерпретирует координаты текстур NaN как »1» или »-1». После тщательного анализа значений он добавил в эмуляцию графики Dolphin условие преобразования NaN в 1, чтобы временно решить эту проблему.
С этой дополнительной обработкой веки выглядят гораздо ближе к тому, что мы видим на консоли.
В Shadow the Hedgehog по-прежнему остались кое-какие странности с рендерингом век, но на данный момент ситуация сильно улучшилась. К сожалению, если вы используете Ubershaders D3D11 или D3D12, то точно эмулировать это поведение не удастся. D3D11/12 автоматически оптимизирует попытки Dolphin использовать isnan для проверки наличия значений NaN в шейдерах, как бы мы ни пытались сказать им, что нам действительно нужно знать, NaN или нет. Из-за этого пока глаза в D3D11/12 при использовании Ubershaders остаются сломанными.
5.0–14829 — PowerPC: Implement Broken Masking Behavior on Uncached Writes, JosJuice при поддержке eigenform, delroth, phire, marcan, segher, Extrems и Rylie
Сложно найти более крупную группу знаменитых разработчиков эмуляторов и реверс-инженеров GameCube/Wii, работающих над одним изменением. Собрал их вместе не какой-то серьёзный баг в Dolphin и не проблема, касающаяся многих сотен игр. Их собрал вместе странный аппаратный баг, попытки протестировать его и в конечном итоге сэмулировать. На самом деле, этот аппаратный баг был известен довольно давно, но его игнорировали, потому что ни в одной коммерческой игре он не использовался… до недавнего времени.
Нам уже было хорошо известно, что игры серии Zelda для N64 были невероятно поломанными. Благодаря выполнению произвольного кода (Arbitrary Code Execution, ACE) игроки в буквальном смысле записывали какой-нибудь код в память и заставляли исполнять его, чтобы перейти сразу к финальным титрам игры. Благодаря этому время спидранов версии Ocarina of Time для N64 стало меньше десяти минут. К сожалению, пока ACE было невозможно на версиях Ocarina of Time и Majora’s Mask для Virtual Console, из-за чего игроки были вынуждены искать альтернативы и новые идеи.
Одно из удивительных открытий, изначально сделанное MrCheeze, называется LightNode SRM. Это более мощный способ манипуляций с устаревшими ссылками (Stale Reference Manipulation) (в мире программных уязвимостей более известный как Use-After-Free или UAF), который работает лучше в версиях для Virtual Console, и выполняется довольно быстро. Он работает и в Ocarina of Time и в Majora’s Mask, и сегодня используется для самого быстрого прохождения OoT в категории Any%! [Прим. пер.: в этой категории игроки стремятся как можно быстрее добраться до финальной катсцены/титров игнорируя прохождение сюжета, выполнение квестов и собирание предметов.]
Работа нового бага на консоли.
Что же такое LightNode SRM и почему оно работает лучше с версиями этих игр для Virtual Console? Давайте рассмотрим сам баг. Важнейший компонент срабатывания бага заключается в том, чтобы найти способ заставить Линка нести «актора» (игровую сущность), который уже был выгружен. Один из простейших способов добиться этого — сменить комнату в состоянии задержки захвата параллельно с использованием классического приёма superslide.
Как только Линк начинает нести ничего, начинается самое веселье. На самом деле он записывает три слова и два полуслова в части памяти, которые принадлежали актору, но теперь используются для других данных. Даже если вы выполните этот глитч для большинства акторов, то всё равно будете ограничены возможностью перезаписи только частей кучи актора, которые содержат такие элементы, как данные о врагах и предметах. Это достаточно полезная возможность, но если найти способ выбраться за пределы кучи актора, то откроется огромный потенциал для взлома. Именно здесь вступает в дело LightNode SRM!
LightNode SRM названо так, потому что использует освещение в игре. Игра обрабатывает загружаемые/выгружаемые источники динамического освещения при помощи двунаправленного списка всех загруженных на текущий момент источников. Одним из примеров таких источников являются разбросанные по всей игре факелы.
Во время LightNode SRM огонь «схваченного» игроком LightNode отсутствует!
Важно здесь то, что при каждой выгрузке актора с источником динамического освещения, соответствующий ему LightNode удаляется из связанного списка:
node->prev->next = node->next;
node->next->prev = node->prev;
Указатель на узел источника (node
в этом фрагменте кода) хранится в данных экземпляра актора, поэтому его можно переписать выполнением SRM и изменить так, чтобы он указывал на управляемую спидраннерами область памяти. Это означает, что node->prev
и node->next
могут быть чем угодно и указывать на всё, что захочет модифицировать спидраннер, даже за пределами кучи актора!
По сути, это даёт спидраннерам возможность выполнять в обеих играх произвольные записи в ОЗУ! Так как манипулирование узлом node
выполняется указанием на координаты респауна Линка, адрес записи и записываемое значение в конечном итоге управляются позицией Линка. На оборудовании Nintendo 64 предоставляемые этим трюком возможности чуть более ограничены, чем на консолях с PowerPC из-за особенностей поведения ЦП в некоторых ключевых ситуациях. В Ocarina of Time это в конечном итоге было не так важно, потому что имя файла было выровнено и находилось достаточно близко к доступу из связанного списка. Заставив указатель LightNode считать имя файла, вы можете записать в название файла полезную нагрузку.
В Majora’s Mask всё устроено немного иначе — из-за использования N64 Expansion RAM имя файла находится слишком далеко в памяти, поэтому использовать его чуть сложнее. Здесь ещё большую важность приобретает способность GameCube/Wii выполнения невыровненных операций записи. Она даёт игрокам гораздо больший контроль над тем, какие значения можно записывать в память, и позволяет им управлять записью в ОЗУ значений с плавающей запятой. Благодаря этому версии этих игр для GameCube и Virtual Console способны на вещи, невозможные на оборудовании N64. Так как версии для Virtual Console быстрее и стабильнее, чем эмуляторы GC N64, спидраннеры продолж