Точность требует мощности или в поисках идеального эмулятора SNES

Точность требует мощности или в поисках идеального эмулятора SNES

Эмуляторы для винтажных игр становятся все более популярными в этих ваших Интернетах, а аргументы в спорах о качестве все больше скатываются к утверждению, что мол, для каждой игры нужно подбирать индивидуальный эмулятор. Сегодня мы рассмотрим точку зрения разработчика эмулятора Super Nintendo — bsnes. Он делится своими мыслям об очень важном аспекте эмуляции — точности. Осторожно! Много букв и технических терминов.

Для того, чтобы запускать старенькие Nintendo или SNES  игры на современном PC — много ресурсов не требуется. Эмуляторы могли работать еще в далеком 1990ом году на жалких 25 мегагерцах. Но вот эмулировать эти старые консоли точно — это уже совершенно другая задача, требующая больших вычислительных мощностей. Точные эмуляторы могут потребовать «честного» 3х-гигагерцового процессора для точной передачи старой технологии. Далее мы рассмотрим, почему точность так важна для эмуляции и почему ее так сложно достичь.
Точность требует мощности или в поисках идеального эмулятора SNES
Говоря бытовым языком — точность — это мера, насколько хорошо эмулятор «прикидывается» оригинальным железом. Совместимость — это также некий критерий точности. Будет ли работать игра на моем новом эмуляторе ? Такой подход («работает — не работает») лишь сглаживает массу мелких проблем, но не решает их. По правде говоря, многие программные эмуляторы работают с большой «погрешностью» по отношению к скоростным характеристикам и будут работать вполне сносно, даже если точность соблюдается лишь на 20%.

Итак, вопрос ставится таким образом: если мы можем достигнуть базовой совместимости и работоспособности, зачем вообще вводить какие-то улучшения, которые стоят нам больших потерь в скорости работы ? Причин две: производительность и preservation (в русском тяжело найти аналог, речь идет о сохранении наследия старых игр. Так что давайте называть это в дальнейшем «ответственное хранение»).

К вопросу о производительности. Взглянем на игру Speedy Gonzales. Это платформер, у которого нет функции «сохранения игры» и он рассчитан на 2-3 часа игры. На первый взгляд он отлично работает в любом эмуляторе. Но как только вы добираетесь до уровня 6-1, вы очень быстро замечаете разницу между быстрым эмулятором и точным: в уровне присутствует некий выключатель, который нужно найти, чтобы закончить игру но в какой-то момент игра виснет, потому что какая-то аппаратная «примочка» сэмулирована неправильно. Нетрудно понять, какие чувства испытывает игрок, только что потерявший 3 часа жизни. Пока софтверная эмуляция не сможет работать точно также, как целевая «железка» — игра остается «непроходимой».

Ну, или Air Strike Patrol, где тень отрисовывается под вашим самолетом. Это сделано с помощью растрового эффекта, основанного на «сканлайнах» (тех полосках, из которых состоит телевизионное изображение на «стеклянном» телевизоре). И для эмулятора это является очень тяжелой и ресурсоемкой задачей. Но, без этого эффекта тень не появится (см. скриншот ниже). Это очень просто не заметить, особенно, если вы не знаете, что там должно быть. На самом деле, тень в этой игре очень полезная штука — ваш самолет может бросать бомбы, ориентируясь по ней. А без нее целиться становится проблематично.

Timecop — ZSNES & bsnes

Второй вопрос — «ответственное хранение». Вот, например Nintendo Game & Watch («Ну, Погоди» в реалиях РФ). Устройства появились в 1980ом году, и, несмотря на то, что их выпустили в количестве 43 миллионов штук, многие не дожили до сегодняшних дней. Правда их все еще можно найти, но стоимость их в глазах коллекционеров будет лишь расти, так как новых устройств не производится. Тоже самое относится к любому «железу. Оно приходит и уходит и эмуляторы являются единственной возможностью ощутить всю прелесть старых игр, и их первоочередная задача — работать точно.

Правда точность «выливается в копеечку». Если эмулятор работает в 2 раза точнее, это значит, что работать он будет в 2 раза медленнее. В нашем мире точность мало кто ценит, так как все «вроде как работает» и даже более-менее играбельно. Многие эмуляторы достигают 95% совместимости при оптимальной производительности.

Ничего плохого в менее точных, но скоростных эмуляторах нет. Они могут работать на сотовых телефонах или карманных приставках. Они подходят для работы на нетбуках или ультрабуках. Но мы должны сказать слово в защиту точности, ведь она тоже важна.

Сделай это программно

В конце 90ых Nesticle был, пожалуй, лучшим эмулятором, который требовал всего лишь 25Мгц-систему для работы. Такая производительность достигалась немалой ценой — образы (ромы) были специально переделаны для работы в этом эмуляторе. Любительские переводы и хаки, рассчитанные на работу в эмуляторе не работали на реальном железе, но дали дорогу целой волне «переделок». В это время особо никто не заморачивался, как выглядели игры в оригинале, всех волновал вопрос работы на эмуляторе — ведь это позволяло избавиться от «пылесборников» и консолидировать коллекцию игр в одной точке — на PC.

Сегодня доминируют эмуляторы Nestopia и Nintendulator, работающие на 800Мгц и на 1.6Ггц соответственно. Такие ресурсы заявлены не потому что эмуляторы не оптимизированы, дело в том, что они достаточно точно эмулируют старое NES-железо.

Ну, или сравним это со старым N64 эмулятором, UltraHLE, чьи системные требования — Pentium 2@350Mhz. Неправда ли, странно наблюдать, что Mario 64 требует несколько меньше ресурсов, чем оригинальные Mario Bros

Мой опыт эмуляции сосредоточен на SNES, а именно — создание эмулятора bsnes. Я вдохновился идеей, стоящий за Nestopia и хотел воссоздать уровень точности, но только для Super Nintendo. И так уж вышло, что тот же уровень работы «взвинтил цену» до отметки 2-3Ггц, в зависимости от игры.
Точность требует мощности или в поисках идеального эмулятора SNES

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

Почему точность имеет значение

Так все-таки, если эмулятор вроде запускает все игры «правильно», что еще нужно в нем улучшить ? Простой ответ — вещи, о которых вы не знаете, как например менее популярные игры.

Например, сравните анимацию из заставки Legend of Zelda на ZSNES и bsnes. На первом все части закончат вращения «слишком быстро», так как процессор работает на 40% быстрее оригинала. Это все мелочи, но если вы заботитесь о точности — это натурально выбешивает.

Я видел дюжину ромов со странными глюками. Иногда, правильная, более точная эмуляция приводит к «неправильному» результату. Так, например Super Bonk’s рассинхронизируется в одном из режимов, что приводит к тому что Bonk зависает. А Starfox безбожно тормозит в куче мест в игре. Это все последствия «допусков», таких как округление числа «пи» до трех и так далее.

Я не против того, чтобы вносить улучшения в классические игры — эмуляторы N64 используют умопомрачительные текстуры высокого разрешения и масштабирование до 1080p, а эмуляторы SNES проводят «двойное сглаживание» для режима Mode7 и кубическую сплайновую интерполяцию для аудио. Такие игры выглядят и звучат лучше. Ничего плохого. Но это расходится с идеей ТОЧНОЙ эмуляции. Ну а совмещение улучшений и точности еще больше усложняют задачу.

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

Вот несколько примеров. Фанатские переводы Dragon Quest 1&2, Dual Orb 2, Sailor Moon: Another Story и Ys 4 страдали от проблемы «невидомого текста», из-за того, что в видеопамять происходила запись во время того, как видеопроцессор был занят отрисовкой скрина. И только половина таких игр была исправлена.

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

Но и это еще не все. Оргигинальное железо имело задержки при опросе математического сопроцессора при операциях деления и умножения. Коммерческие игры «знали» об этом, но фанатские переводы Zelda имели проблемы с музыкой, а Super Mario World требовал дополнительного патча.

Или, к примеру эмуляторы могут игнорировать факт, что звуковой процессор пишет сэмплы в общую память. Это не проблема, до тех пор, пока ваши хаки не начинают использовать нереальные размеры буфера, который в конечном итоге перезаписывает кусок себя в памяти, возникает ошибка, все виснет. Такая штука присутствует в десятке фанатских уровней Super Mario World, которые на реальном железе или точном эмуляторе не играбельны.

Свой эмулятор для каждой игры ?

Настанет день, когда пользователю потребуется ZSNES v1.42 для четырех переводов, Snes9X v1.51 для шести хаков и bsnes v080 для нескольких загадочных японских игрушек. Это прискорбно.

Вы должны понимать, что эмуляторы тоже имеют жизненный цикл. Это особенно верно для ZSNES, написанном на чистом x86 ассемблере. Вы просто не можете запускать его на своем мобильном телефоне. Делая хак, который работает только на ZSNES вы обрекаете свой труд на прозябание in the middle of nowhere. Как только Windows прекратит поддержку 32-разрядных приложений, так же, как это уже было сделано 16-битными — эти переводы и хаки будут потеряны навсегда. Эмулятор превращается в очередную устаревшую консоль, вместо того, чтобы поддерживать жизнь платформы.

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

3Ghz ? Правда ?

Вполне реально написать хорошо оптимизированный, быстрый эмулятор SNES, работающий плавно на процессоре со скоростью 300Mhz. Но при этом вы обязательно огребете кучу странных ошибок.

Это обычно случается, когда проблемы решаются «хакерскими средствами». ZSNES и Snes9X содержат внутренний список 50ти самых популярных игр. Когда вы грузите эти игры, эмулятор подстраивает временные характеристики и патчит некоторые области кода перед запуском. Это тянется еще со времен Nesticle, когда игры патчились заранее, но все равно — это жульничество, как бы это не выглядело.

Обычный геймер, которому известны лишь порядка 20 популярных игр не видит разницы между эмуляторами «для 300Мгц» и «тем, который на 3Ггц», и конечно он выберет вариант попроще. Я, безусловно, уважаю и ценю вариант «быстрых» эмуляторов, но если нужна точность, «быстрый» подход не сработает. Чем больше геймеров использует «точные» эмуляторы, тем больше «багов» будет найдено в играх, которые в нем поддержаны. И сделано это будет не «специальным хитрым патчем под одну игру», а честным фиксом точности эмулятора.

Скриншот ниже — отличная иллюстрация нишевой игры. Вообще, это хороший платформер, но слышали о нем немногие. Это как раз тот самый пример, почему популярные игры идут в «быстрых» эмуляторах гладко, но точность тоже важна. Вы никогда не узнаете, почему «не столь популярная игра» работает криво. Возвращаясь к скриншотам ниже — тут тумблер. Когда на него нажимают в любом другом эмуляторе — игра виснет. То, что должно произойти — опять таки на скриншотах — тумблер перемещает блок в центр электрического поля. Это требуется по сценарию игры для того, чтобы закончить уровень, да и игру тоже. На момент написания статьи bsnes был единственным эмулятором, на котором эту игру можно пройти.

У SNES было не только режим высокого разрешения, но и так называемый «pseudo-hires mode». Он применялося для alpha-blending между слоями, который выполнялся прямо на железе. Игнорирование этого режима приводило к неприятными последствиям. Скриншот ниже.

Точность требует мощности или в поисках идеального эмулятора SNES

Видеоигры — часть истории. И мы должны уважать ее, сохраняя игры в том виде, в котором они выпущены. Представьте себе, что в мире остался только JPEG-вариант Моны Лизы, RealVideo запись посадки на луну или MIDI версия браденбургского концерта какого-нибудь. Возможность сохранить историю есть и этим нужно воспользоваться.

А где остальные 2.7Ghz? Синхронизация

Одно из главных заблуждений при создании эмулятора и настройки производительности — достаточно, мол, сэмулировать CPU на нужной скорости. Это не так, к сожалению. Скорость процессора N64 в 35 раз выше, чем у SNES, однако UltraHLE требует, вобщем, тех же ресурсов, что и ZSNES.

Первичная потребность эмулятора — синхронизация центрального процессора с остальными компонентами. Эмуляция — процесс довольно последовательный. Попытка опираться на мощь многоядерных процессоров сегодня часто приводит как раз к ошибками синхронизации. Представьте себе сборочных цех — один человек разгружает коробки, второй осматривает, третий открывает, еще один что-то собирает… Синхронизация — это тот момент, когда на сборочной линии все замирает, очищается и начинается сначала, при этом с новым продуктом. Это большой удар по общей производительности. Тут нафиг не нужны ни предсказания ветвлений, ни конвейеры (то, чем хвастают современные системы). Чем больше нужно синхронизировать, тем быстрее движется ваша сборочная линия, чтобы успеть.

Сравним уровень синхронизации ZSNES и bsnes:

S-CPU: 600,000 vs 21,477,272
S-SMP: 256,000 vs 24,576,000
S-DSP: 32,000 vs 24,576,000
S-PPU: 15,720 vs 21,477,272
Total: 903,720 vs 92,106,544

Начнем с процессора, который должен работать на 3.58Мгц. Это количество циклов, выполняемых в секунду. Обычная инструкция занимает от 4х до 8ми циклов, и ZSNES синхронизируется «раз за инструкцию». Но если «копнуть глубже», циклы еще и разбавляются задержками шины, которое тоже требуют временных затрат и регулируются кварцевым генератором. Кварц SNES рассчитан на 21.47Мгц.

Когда речь заходит от видео, 99% игр не пытаются менять регистры дисплея, пока идет прорисовка. Это позволяет прорисоваться всем строкам за раз, то есть 262 строки умножаем на 60 фреймов в секунду синхронизации. Но в играх вроде Air Strike Patrol, где запись в видеорегистры идет несколько раз в момент прорисовки одной строки (для регулировки яркости) вы должны синхронизироваться каждый такт уже не процессора, а генератора, если хотите достичь максимальной точности.

Если говорить о звуке, все игры идут нормально, если вы синхронизируетесь согласно частоте звука, то есть с частотой 32кГц в случае со SNES. ЗапуститеEarthworm Jim 2 и вы обнаружите, что звук «обрезается», если не синхронизироваться за каждый такт. Koushien 2 так вообще подвисает.

Пусть bsnes работает медленне ZSNES в 10 раз,зато он в 100 раз точнее. По правде говоря, на скорости в 3Ггц все выглядит весьма привлекательно. Я использовал кооперативную мультипоточность и синхронизацию в реальном времени, технологии которые никто и никогда не использовал в эмуляциии. Это позволило получить ту производительность, которая действительно нужна. Обычный подход тут бы не сработал.

В принципе, ZSNES с рейтом синхронизации в 100 раз меньше, неплохо работает на большинстве игр. Никто не скрывает, что идеальная синхронизация требуется далеко не всегда. Но есть случаи, когда она нужна. Несмотря на низкую скорость процессора SNES, многие оригинальные игры натурально выжимали все соки из железа.

Если не стремиться к правильным временным характеристиками, то это будет игра whack-a-mole. Убил суслика — на его месте появилось трое. Починил 1 баг -вылезло 5. Только гляньте на changelog’и за последние 15 лет.

Эмуляция дополнительных процессоров

Один из самых интересных аспектов систем с картриджами состоит в том, что вы реально втыкаете плату в свою систему. Таким образом, вы можете добавлять новые сопроцессоры, часто DSP (digital signal processor) прямо вместе с картриджем. Это дает огромное конкурентное преимущество перед конкурентами. Самые популярные сопроцессоры на SNES — SuperFX для рендера полигонов и вращения спрайтов (использовался в Starfox и Super Mario World 2) и DSP-1 для 3х-мерной математики (использовался в Pilotwings and Mario Kart.)

Часто эти сопроцессоры отделены от процессора-хоста и их можно сэмулировать с помощью HLE — high level emulation. Это не уникально для сопроцессоров SNES — также это используется в эмуляции микрокода видеопроцессора N64, да и не только там

Тут самое главное — не думать об индивидуальных инструкциях, а расценивать их как единое целое. Другими словами — «отрендерить треугольник с этими точками» или «повернуть спрайт на N градусов». Получается, что можно выполнить эти операции без накладных расходов. К сожалению это напрочь отметает возможность точного расчета временнОй информации, к примеру, сколько требуется для выполнения той или иной инструкции. Хотя с другой стороны это приводит к хорошим результатам — в целом все рендерится и поворачивается «как надо».

LLE (low-level emulation) для DSP заключается в обработке команд как у отдельного процессора: выполнять инструкцию за инструкцией. Игры в этом случае работают с нужной скоростью, даже в «граничных условиях». И конечно, это требует ресурсов. Так, Super Mario Kart работает шустро в режиме HLE а Super Mario World, игра без сопроцессора работает на 25-30% медленее в режиме LLE.

LLE — процесс дорогой во всех смыслах. Для «снятия» прошивки DSP нужно растворить корпус азотной кислотой, просканировать поверхность электронным микроскопом, фактически вручную «считать чип». Эта работа стоит миллионы долларов, если выполняется профессионалами, в зависимости от оборудования и технологий. Персонаж по имени «Dr. Decapitator» выполнил такую работу для сообщества любителей ретро-игр по себестоимости материалов.

Но и когда техническая часть закончена вы должны осознавать, что каждый DSP уникален. Что нужно «реверсировать» кучу кода без какой-либо документации. Процесс отлично иллюстрирует все трудности точной эмуляции.

Ну что, теперь точно ?

Честно говоря, все то, что перечислено — это лишь верхушка айсберга. Вы слышали о DICE — digital integrated circuit emulator ? Этот эмулятор работает на уровне транзисторов для идеальной эмуляции первых видеоигр. Для запуска Pong с 5-10fps DICE требует процессора на 3Ггц. Да, вы правильно поняли. Нет процессора, который смог бы запустить Pong на полной скорости. DICE — не «тормозная» программа. Она реально оптимизирована, но знаете сколько требуется ресурсов, чтобы сэмулировать КАЖДЫЙ транзистор ?

Но однажды это будет возможно. И я буду счастлив, что классика останется доступной для новых поколений.

Применять путь DICE для более современных систем проблематично. Рассмотрим Visual6502. Некоторые неглупые люди использовали технологию «азотной кислоты» для 6502, применяемого в Nintendo и C64. Потом векторизовали картинку и сделали HLE — эмулятор чипа, который не берет в расчет каждую задержку транзистора. Этот код работает даже на Javascript и конечно же переписан на С и оптимизирован. И даже со всеми допусками — современные компьютеры не так быстры, чтобы эмулировать процессоры прошлых поколений ТОЧНО.

Как бы мне не хотелось, чтобы каждый эмулятор работал на уровне транзисторов, это недостижимо. Честно — мы не увидим соответствующего железа, способного эмулировать N64 при нашей жизни 🙂

Скорее всего, это недостижимо и для SNES. Чем мощнее компьютер, тем большей точности хочется.

Компромисс, на который я пошел — сделать грубый дизайн, похожий на реальное железо, отделить каждый процессор, и объединить компоненты только тогда, когда они действительно должны работать вместе. Цель — повторить железо. Реальная цель — сделать опыт эмуляции неразличимым с реальным железом. Но, в отличии от DICE — не идеально.

Точность требует мощности или в поисках идеального эмулятора SNES

Цель — не улучшить железо, но подобраться к нему так близко, насколько это возможно.

Когда речь заходит о N64 и более мощных системах, я понимаю что мой подход не имеет смысла. Тут все сложно, и я точно знаю, что никто никогда не сможет написать эмулятор, работающий быстрее чем 1 FPS на самом мощном железе.

Вместо заключения

Я понял одну вещь — разработчики натурально боятся использовать даже половину вычислительных мощностей сегодняшних систем. Старое железо — вот в чем причина. Все пытаются «меряться» с эмуляторами, написанными много лет назад, может быть не точными, но очень быстрыми.

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

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

Ссылка на оригинал статьи. Перевод и озвучание — Точность требует мощности или в поисках идеального эмулятора SNESgrmretro, специально для Точность требует мощности или в поисках идеального эмулятора SNESemulate_su