Улучшения в эмуляторе Dolphin

в 6:52, , рубрики: dolphin emulator, GameCube, Nintendo 64, nintendo wii, wii, Игры и игровые приставки, обратная разработка, Работа с 3D-графикой, разработка игр, реверс-инжиниринг, эмуляторы
image

Многие сообщества геймеров благодарны разработчикам эмуляторов за их многолетний труд. Эмуляторы — важная часть многих сообществ любителей классических игр, они предоставляют игрокам доступ к таким функциям, как сетевой мультиплеер, моддинг, сохранения, а также открывают усовершенствования, невозможные на консоли. Если вам захочется поиграть в любимую игру, иногда просто удобнее воспользоваться эмулятором на десктопном компьютере, планшете или телефоне, чем откапывать и подключать консоль. Однако важно заметить, что наши отношения с игровыми сообществами взаимны и без помощи игроков и фанатов мы бы не смогли поддерживать библиотеку из тысяч игр.

Основным катализатором многих изменений, описанных в этом отчёте, стали сообщества игроков. Они занимались сложной отладкой, находили мелкие проблемы, которые оставались бы незаметными для тех, кто не знает игру в совершенстве, и даже создавали патчи, чтобы игры лучше подстраивались под усовершенствования в эмуляторе. Весь этот вклад, хотя и не являлся кодом, очень ценим нами, благодаря нему Dolphin стал тем, что мы видим сегодня.

Значимые изменения

5.0-14795 — JIT: Fix FMA Negation Ordering, JosJuice

Inazuma Eleven GO: Strikers 2013 — последний релиз для Wii любимой игроками футбольной серии Inazuma Eleven. Эту игру можно любить за многое — множество персонажей, специальные движения, длинный режим RPG-истории, в которой вы собираете собственную футбольную команду, прокачиваете персонажей и побеждаете противников. Несмотря на то, что игра была выпущена только в Японии, она стала культовой для игроков всего мира. Существуют её фанатские переводы, по ней проводятся турниры между странами и даже есть «Кубок мира»!

Улучшения в эмуляторе Dolphin - 2

В этом году уже прошло несколько турниров и онлайн-соревнований!

Хотя в 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 наконец-то разобрался: оказалось, проблема заключалась в различиях в конкретном моменте смены знака. Давайте рассмотрим технические подробности.

Улучшения в эмуляторе Dolphin - 3

Смена знака — это изменение знака с положительного на отрицательный, или наоборот. Для эффективности она объединяется в дублирующие версии команд 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.

Улучшения в эмуляторе Dolphin - 4


Хотя мы устранили эту проблему в Inazuma, дальнейшие исследования выявили другие возможные проблемы. Описанные выше трюки дают одинаковые результаты на консоли, какие бы данные она ни обрабатывала… но только когда они выполняются обычной математикой. На реальном оборудовании эти уравнения выполняются при помощи математики с плавающей запятой, поэтому снова всплывают давно известные нам погрешности округления операций с плавающей запятой. При смене знака на разных этапах вычисления уравнений, расчёты с плавающей запятой округлялись не так, как в процессорах PowerPC. Обычно это было допустимо, но в пограничных случаях округления, например, при округлении в сторону бесконечности, различия в округлении оказывались достаточно серьёзными, чтобы создать другой результат с плавающей запятой. Не знаю, возникала ли уже в каком-то ПО эта проблема, но по возможности стоит устранять подобные баги.

Чтобы устранить все эти странности, мы теперь просто пользуемся стандартными командами madd и msubnmsub на 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. Поэтому когда игра копирует из памяти фрагмент буфера кадров размером 256x256, при копировании обратно он пропускается через неправильную матрицу проекции и оказывается слегка деформированным до размера фрагмента 256.401 на 256.534. Проще всего представить этот баг, сравнив его с редактированием фотографии. Представьте, что вы скопировали часть изображения, незначительно уменьшили масштаб всего остального изображения, но при копировании фрагмента обратно вы не изменили его масштаб, а потом отмасштабировали полное изображение до исходного размера. Аналогия неидеальна, но, по крайней мере, может дать вам представление о том, какие визуальные проблемы это может вызвать. Но дело в том, что нативное разрешение GameCube настолько мало, что такие незначительные отклонения не приводили к заметным проблемам. Баг может проявляться визуально только из-за того, что Dolphin позволяет использовать повышенное внутреннее разрешение.

Улучшения в эмуляторе Dolphin - 5


При увеличенных разрешениях возникает незначительный излом в пикселях верхнего левого квадранта...

Улучшения в эмуляторе Dolphin - 6


Однако функция округления вершин (Vertex Rounding) полностью его устраняет.

Ко времени выпуска SpongeBob Squarepants: Battle for Bikini Bottom компания Heavy Iron Studios заметила этот баг и скорректировала поведение. Она не только исправила матрицу проекции, сменив размер на 640x480, но и добавила горизонтальное и вертикальное смещение на 1/512 (полпикселя) к позиции и координатам текстур. Благодаря этому всё действительно выравнивается при повышенных внутренних разрешениях, однако теперь размер текстуры составляет 513/512, а не 1.0. Это означает, что копирование EFB захватывает части самого края экрана. Если мы разобьём на части процесс рендеринга изображения, то увидим, как повышенные разрешения ломают картинку.

Улучшения в эмуляторе Dolphin - 7


Это скриншот того, как выглядит игра примерно на середине процесса рендеринга кадра. Мы видим, что тень ещё не наложена.

Улучшения в эмуляторе Dolphin - 8


При нативном разрешении всё очищается на краю экрана.

Улучшения в эмуляторе Dolphin - 9


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

Пользователи, заметившие эту проблему, прозвали её проблемой «синего бокса», потому что чаще всего она дублировала части скайбокса. Хотя Vertex Rounding может исправить координаты позиций, починив таким образом рендеринг теней, он делает ещё более заметным то, что данные берутся с самого края экрана, потому что координаты текстур по-прежнему смещены.

Улучшения в эмуляторе Dolphin - 10


Без Vertex Rounding тени вполне ожидаемо поломаны, а в левом верхнем углу иногда появляется синий бокс.

Улучшения в эмуляторе Dolphin - 11


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 решил портировать в патч и этот код. Однако, кое-что мы упустили.

Улучшения в эмуляторе Dolphin - 12


Имевшийся код для The SpongeBob SquarePants Movie удалял большинство эффектов затенения.

Код для The SpongeBob SquarePants Movie не удалял смещение из исполняемого файла, а полностью исключал из рендеринга проблемные копии EFB! Хоть это и устраняло артефакты, при этом терялось и множество спецэффектов игры. Это решение нельзя было использовать как рабочий патч для игры, включенный по умолчанию. Однако эти игры казались настолько похожими, что JMC47 верил в возможность правильного патча. Чтобы создать его, он ещё раз заручился помощью Pokechu22, чтобы изучить рендеринг игры с кодом action replay и без него. Вместе они убедились в том, что этот код был тупиковым путём для устранения источника проблемы. Однако в процессе этого исследования Pokechu22 сообщил, что код для Battle for Bikini Bottom скорее всего более детализирован не из-за популярности игры, а потому, что на её диске содержались отладочные символы в виде неурезанного исполняемого файла ELF. Отладочные символы чрезвычайно полезны для реверс-инжиниринга, поскольку они разбивают программу на функции и назначают им названия непосредственно в коде. Это сильно упрощает понимание их работы.

Разработчики оставили отладочные символы в предыдущей игре, но могли ли они оставить их снова в сиквеле...?

Улучшения в эмуляторе Dolphin - 13


Джекпот!

Оказалось, что на дисках всех игр Heavy Iron Studios той эпохи присутствовал неурезанный файл ELF. Благодаря этому мучительный проект по реверс-инжинирингу превратился в задачу, с которой при достаточном количестве времени и труда справится даже новичок. Благодаря руководству Pokechu22 пользователь JMC47 научился работать с инструментом для реверс-инжиниринга Ghidra, а также с плагинами, разработанными специально для анализа исполняемых файлов GameCube и Wii. Процесс был медленным, но помощь Pokechu22 позволила с ним справиться. На этот раз смещение было не таким, как в Battle for Bikini Bottom; копирование EFB теперь выполнялось в половинном разрешении, но во всём остальном процесс рендеринга не отличался от предыдущей игры. Pokechu22 смог определить значение, находившееся в памяти, после чего JMC47 начал патчить каждое вхождение числа с плавающей запятой, пока не нашёл адрес памяти, исправлявший рендеринг. Сделав это, он создал новый Fifolog для Pokechu22, чтобы тот убедился в работе патча и портировал код на другие регионы игры.

Улучшения в эмуляторе Dolphin - 14


Даже Патрик удивлён тому, что все баги пропали

… Но и на этом история не заканчивается. 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 имели патчи, обеспечивавшие правильную работу в высоких разрешениях.

Улучшения в эмуляторе Dolphin - 15


Из-за сломанных теней игру приходилось запускать в нативном разрешении.

Улучшения в эмуляторе Dolphin - 16


Но теперь можно играть почти в любую из старых игр 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, и нашёл нечто очень любопытное.

Улучшения в эмуляторе Dolphin - 17


Вот как рендерится Fifolog в Dolphin.

Улучшения в эмуляторе Dolphin - 18


Но на консоли Fifolog рендерится корректно, то есть на ней существует какая-то специальная обработка NaN!

Походило на то, что реальное «железо» каким-то образом автоматически исправляет NaN. Pokechu22 продолжил разбираться с проблемой на консоли, в конечном итоге поняв, что консоль интерпретирует координаты текстур NaN как «1» или "-1". После тщательного анализа значений он добавил в эмуляцию графики Dolphin условие преобразования NaN в 1, чтобы временно решить эту проблему.

Улучшения в эмуляторе Dolphin - 19


С этой дополнительной обработкой веки выглядят гораздо ближе к тому, что мы видим на консоли.

В 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 названо так, потому что использует освещение в игре. Игра обрабатывает загружаемые/выгружаемые источники динамического освещения при помощи двунаправленного списка всех загруженных на текущий момент источников. Одним из примеров таких источников являются разбросанные по всей игре факелы.

Улучшения в эмуляторе Dolphin - 20


Во время 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, спидраннеры продолжили работать с ними.

Первое применение LightNode SRM дало свои плоды в Majora's Mask в категории Any%; спидран не поставил мирового рекорда, но всё равно показал потенциал новой техники. Вскоре после этого LightNode SRM прославилось тем, что впервые позволило пройти меньше чем за 7 минут любую версию Ocarina of Time! Этот способ работает только на GameCube/Wii из-за ещё одного поведения ЦП, вызывающего явление, которое спидраннеры называют DoubleWord Write (DWW) и QuadWord Write (QWW). Мы вернёмся к нему чуть позже, потому что объяснение его довольно сложно.

С точки зрения спидраннинга, эти техники открывали множество новых возможностей, особенно вне категории Any%. Выполнение произвольного кода — настолько мощная техника, что запрещено во многих категориях, чтобы не усложнять определения категорий и сохранять интересность прохождения. Если у вас получилось исполнять собственный код, то вы можете сделать что угодно. Стоит заметить, что запрет ACE включает в себя использование LightNode SRM для перезаписи кода, но так как его можно использовать для перезаписи данных, что совершенно законно, оно сильно повлияло на множество различных категорий.

Как и в случае с любым важным багом, игроки начали стремиться расширить его через эмуляцию. На этот раз они использовали не эмулятор N64, потому что лучше всего для спидранов подходят версии для Virtual Console Nintendo Wii. К сожалению, как понятно из представленного выше видео, Dolphin не очень хорошо подходит для этой задачи. Хотя все основные шаги работали, значения, записываемые в ОЗУ при помощи LightNode, немного различались на консоли и в Dolphin. Причина этого может быть немного неожиданной: они использовали функцию, которая работала в Dolphin, но была поломана на консоли.

Именно так — трюк зависел от точной эмуляции Uncached Writes.

Улучшения в эмуляторе Dolphin - 21

На Nintendo GameCube и Wii есть аппаратная особенность, вызывающая неправильное поведение невыровненных некэшированных операций записи. Для Dolphin это не было особой проблемой, потому что в коммерческом ПО такие операции записи не использовались. Не было никакого смысла прикладывать усилия для эмуляции «мёртвой» функции консоли. Однако давайте вспомним о той функции ЦП, которая вызывала DWW и QWW. Это были именно те самые поломанные невыровненные некэшированные операции записи! Их поломанность позволяла перезаписывать больше памяти, чем было бы возможно при правильной работе. Это и было ключом к спидрану — в показанном выше видео с переходом к титрам игры автор переписал две соседние записи входа, чтобы вызвать две разные катсцены с титрами в Termina Field!

К сожалению, в Dolphin это не работало. Эти некэшированные операции записи вели себя правильно, то есть сломанное дублирование не эмулировалось и вторая запись входа не записывалась. Спидраннеры Majora's Mask обратились к разработчикам Dolphin с вопросом: можно ли заставить этот способ работать?

Отчёт о проблеме был отправлен, спидраннеры уже были готовы тестировать игру, а JosJuice начал разрабатывать тест оборудования, чтобы разобраться, что же конкретно происходит. К сожалению, он почти сразу же зашёл в тупик. Оказалось, что попытка проверки поведения на консоли приводит к внезапному сбою. Что ни делали тестеры, некэшированные операции записи завершались зависанием консоли. К анализу происходящего привлекли других разработчиков. Консоль не должна была зависать; мы знали это, потому что спидран показал, что, по крайней мере, это должно работать. Постепенно всё больше разработчиков начинало разбираться в проблеме, и вскоре вокруг неё собрались реверс-инженеры с огромным опытом. Было протестировано множество разных подходов, одни разработчики пытались воссоздать условия игры, другие пробовали упростить тест, чтобы понять, не возникает ли ошибка в другом фрагменте теста.

Но что бы ни происходило, консоль зависала на первой некэшированной записи.

Спустя несколько дней экспериментов eigenform решил головоломку. Почти все homebrew-проекты созданы на основе homebrew-библиотеки libogc, используемой для обеспечения интерфейса с оборудованием GameCube и Wii. Она сильно упрощает написание, компилирование и тестирование homebrew-программ, предоставляя API для взаимодействия с оборудованием и имея множество примеров проектов. eigenform решил написать тест, не использующий libogc. Хотя этот способ был гораздо более сложным, в конечном итоге он подтвердил, что проблема связана с самой libogc. К анализу были привлечены уже десятки разработчиков, поэтому потребовалась всего пара минут для выяснения того, что зависание было вызвано libogc, забывающей сбросить прерывание; из-за этого библиотека снова и снова обрабатывала одно и то же прерывание. Благодаря тестированию этот баг устранён в последних версиях libogc.

После того, как тесты оборудования начали работать, JosJuice смог протестировать и понять, как именно некэшированные тесты работали на консоли, и реализовал их сломанное поведение в Dolphin. Мы попросили сообщество спидраннеров убедиться, что всё работает правильно, и они продемонстрировали нам безошибочное прохождение в Dolphin версии Majora's Mask's для Virtual Console в категории Any%.

После внесённых изменений Rylie подтвердила, что прохождение работает в Dolphin!

Без Rylie и безумных сообществ любителей Ocarina of Time и Majora's Mask мы могли и никогда не узнать, что некэшированная запись могла использоваться в коммерческой игре для чего-то полезного…

На самом деле, нам известен один конкретный homebrew, который использовал это поведение в качестве меры защиты. Версии Homebrew Channel с закрытыми исходниками имели множество защит и странных поведений, использовавшихся для того, чтобы их запускали надёжным образом. Одной из функций, которые они использвоали, было поломанное поведение некэшированных записей. Мы даже не занимались этим приложением, потому что в те времена Dolphin был настолько ненадёжен, что мы и не надеялись его запустить. Но годы улучшений изменили ситуацию, и при наличии поддержки невыровненных кэшированных операций записи версии Homebrew Channel с закрытыми исходниками наконец-то начали проявлять в Dolphin признаки жизни. На самом деле, приложение позволяло даже добраться до меню… однако с некоторыми особенностями.

Улучшения в эмуляторе Dolphin - 22


Если защиты в старой версии Homebrew Channel выполнялись неправильно, они не позволяли пройти уведомление о жульничестве. Однако спустя час ожидания они всё равно самостоятельно позволяли загрузить меню.

Улучшения в эмуляторе Dolphin - 23


Однако они демонстрировали этот дружелюбный жест.

Некоторые из наших пользователей могут задаться вопросом: как же им удавалось запускать Homebrew Channel в Dolphin. Дело в том, что последняя версия Homebrew Channel (называющаяся Open Homebrew Channel) избавилась от всех защит, чтобы упростить работу Dolphin. Так как большинство злодеев, использовавших канал в своих целях, уже давно перешло на более современные консоли, защиты не добавляли ничего, кроме головной боли для разработчиков Dolphin. Тем не менее, всё равно было бы здорово победить все проверки в старых версиях Homebrew Channel и заставить их загружаться без срабатывания защитных процедур.

5.0-14844 — Implement Late VI Updates, Techjar и phire

Большая часть работы по выводу кадров в Dolphin заключается в создании оптимизаций, обеспечивающих эмулятору минимальные задержки. Хотя большинство игр упрощает работу благодаря использованию стандартной конфигурации Video Interface (VI) и позволяют Dolphin обходить большую часть эмуляции XFB, снижая задержку сильнее, чем это возможно на консоли, многие игры применяют более сложные конфигурации VI. Это заставляет Dolphin делать всё правильно и на самом деле эмулировать процедуру считывания данных. Но даже в этом случае Dolphin всё равно немного жульничает, выводя копию XFB с параметрами, которые она имела в начале поля, а не применяя их на протяжении процесса вывода копии XFB. Это позволяет сэкономить примерно 16 мс задержки. Считалось, что такая техника поддерживается всеми играми… пока на горизонте не появилась WWE Crush Hour.

Представьте это мерцание с частотой 60fps. Видео с полной скоростью можно посмотреть здесь (опасно для эпилептиков).

Эта очень странная игра обладает поведением, которое никто не встречал ни в одной коммерческой игре: она меняет параметры VI во время вывода кадра на экран. Dolphin ничего не может с этим поделать, потому что уже закончил обработку с неправильными параметрами VI к тому времени, как игра их изменила. Спустя четыре года после некорректного анализа ZephyrSurfer повторно проанализировал эту проблему и понял, что предыдущее внедрение в Hybrid XFB было неверным. Этот новый анализ привёл к появлению версии 5.0-146 и к оптимизации задержек.

Увидев это, phire рассказал всем о хаке задержки и объяснил, как обойти эту проблему. По сути, в Dolphin просто нужно было добавить опцию ожидания конца вывода для правильного вывода кадра. Это приводит к дополнительной задержке ровно в один кадр, поэтому было предложено реализовать эту функцию как отдельную опцию только для этой игры. Хотя оба разработчика были слишком заняты, оставленные ими объяснения оказались достаточно чёткими для того, чтобы Techjar смог реализовать это исправление. Важно заметить, что ни одна из этих реализаций не является точной; чтобы делать всё правильно, Dolphin должен был бы применять конфигурации VI во время вывода, что было бы гораздо сложнее, но почти не принесло бы пользы.

5.0-14866 — D3D12 — Fix GPU Texture Decoding on AMD, K0bin

Новый участник проекта K0bin обратил внимание на отсутствующий барьер памяти в бэкенде D3D12 эмулятора Dolphin, который мог бы вызывать проблемы с декодированием текстур в GPU. Драйверов NVIDIA это не коснулось (вероятно, из-за игнорирования переходов между состояниями), но в картах AMD включение GPU Texture Decoding вызывало серьёзные проблемы и сбои. Проблему удалось решить одной строкой кода.

Улучшения в эмуляторе Dolphin - 24

Здесь бы мог быть скриншот 6900 XT с устранённой проблемой, если бы у нас была эта карта!

5.0-14821, 5.0-14833, 5.0-14897 и 5.0-15019 — Fix dcbx Invalidation Performance Without Breaking Everything This Time, AdmiralCurtiss и JosJuice

Если вы следили за июльскими тестовыми сборками, то могли заметить тенденции в изменениях с dcbx (инвалидация/сброс/обнуление кэша данных и т.п.). Наша цель заключалась в том, чтобы масштабные инвалидации были быстрыми и корректными, но достижение обоих требований оказалось сложной задачей. В конце июльского отчёта Progress Report мы решили, что у нас есть простое исправление снижения производительности, касающегося различных команд сброса/инвалидации кэша данных. Казалось, что в обоих поломанных случаях всё работает хорошо, и разработчики подумали, что эта сага подошла к своему завершению. Как же мы ошибались…

После выпуска Progress Report к нам начали поступать отчёты о проблемах, и самые частые были связаны с серией игр Mario and Sonic at the Olympic Games. Первоначальный анализ показал, что всё было очень плохо. JIT архитектуры x86-64 эмулятора Dolphin вёл себя неправильно и дважды транслировал адрес во время dcbx, таким образом переходя к неправильному флагу. Также в обоих JIT Dolphin было поломано маскирование, из-за чего поломанными в конце месяца оказались довольно многие игры.

JosJuice и AdmiralCurtiss объединили усилия, чтобы быстро исправить JIT и как можно быстрее снова заставить всё работать. JosJuice занялся исправление маскирования в JIT AArch64, а AdmiralCurtiss внёс гораздо более объёмные изменения в JIT x86-64, чтобы гарантировать, что Dolphin всегда будет передавать командам dcbx правильный адрес.

Благодаря этой быстрой работе менее чем через две недели всё снова заработало. Однако эти исправления имели свою цену. Из-за них пропали все улучшения производительности из предыдущего отчёта об изменениях, то есть Arc Rise Fantasia и другие игры, одновременно инвалидирующие большие области памяти, снова имели проблемы с производительностью. Проще говоря, ситуация была не самой хорошей, и для её исправления требовались усилия.

Улучшения в эмуляторе Dolphin - 25


Загрузка областей с карты мира приводила к серьёзному проседанию FPS, поскольку игра очищала большие участки памяти.

AdmiralCurtiss приступил к изучению причин торможения, чтобы найти виновника. При первоначальной загрузке Super Mario Sunshine, которая является одним из наихудших сценариев для dcbx, код трансляции страниц вызывался 134 миллионов раз. Что ещё страннее, так это то, что инвалидируемые игрой данные даже не отображались на физическую память! Выполнение всех этих вызовов по отдельности было ужасно неэффективным, поэтому нужно было что-то сделать, чтобы их сгруппировать. Мы решили поискать подсказки в том, как работает idleskipping. Idleskipping — это функция в JIT Dolphin, ищущая в коде циклы, предназначенные просто для «сжигания» излишнего времени ЦП. Вместо того, чтобы эмулировать эти пустые операции, мы можем просто обнаруживать и пропускать их, при этом подстраивая downcount и другие аспекты, чтобы сильно увеличить производительность ЦП.

Хотя dcbx не является пустой операцией наподобие idleloops, благодаря распознаванию их циклов AdmiralCurtiss смог сделать так, чтобы вместо выполнения сотен миллионов отдельных вызовов Dolphin статически анализировал ситуацию для объединения их в одну крупную dcbx, а затем подстраивал downcount и другие вещи, чтобы в конечном итоге оптимизация с точки зрения эмулируемого окружения оказывалась эквивалентом отдельных вызовов. Этот трюк восстанавливает производительность до уровней, которые были в этих играх раньше и при этом больше ничего не ломает.

И JIT x86-64, и JIT AArch64 теперь оснащены этой новой оптимизацией (для AArch64 её реализовал JosJuice). И теперь всё должно быть и быстрым, и корректным, а нам не придётся выбирать одно из двух, как это было в последние два месяца.

Автор:
PatientZero

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js