Перевод четвёртой статьи из серии от Fabien Sanglard, в этот раз про порт Another World на IBM PC.
В течение трёх десятилетий IBM спокойно доминировала на рынке мэйнфреймов. Когда в 1979 году продажи микрокомпьютеров достигли 150 миллионов долларов, «Колосс Армонка» решил выпустить собственный. На фоне конкурентов, таких как Hewlett-Packard (HP), Texas Instruments (TI), Tandy и Data General, IBM сделала всё по-другому, чтобы выделиться.
![](https://habrastorage.org/webt/r1/w6/ky/r1w6kydx5kwmbycw6ngmhkvpmhw.png)
Серия статей
- Полигоны Another World.
- Полигоны Another World: Amiga 500.
- Полигоны Another World: Atari ST.
- Полигоны Another World: IBM PC.
- Полигоны Another World: Sega Genesis.
IBM PC
Вместо того, чтобы идти по вертикали, как это было в прошлом, с большинством компонентов и программного обеспечения, разработанных собственными силами, IBM построила свой микрокомпьютер горизонтально. Они приобрели такие элементы, как CPU, у Intel и поставили с операционной системой PC DOS 1.0 от Microsoft.
Они пошли ещё дальше, предоставив технические характеристики и схемы машины. Для потребителей, которые раньше боролись с производителями за технические детали, это был совершенно новый мир.
Техническое справочное руководство IBM PC за 36 долларов США включало в себя полную принципиальную схему, откомментированный исходный код ПЗУ BIOS и другую информацию по проектированию и программированию для всего оборудования IBM, связанного с ПК, а также инструкции по разработке периферийных устройств сторонних производителей.
— Wikipedia (IBM_Personal_Computer#History)
Первый персональный компьютер от IBM был выпущен 12 августа 1981 года с появлением 5150. Он работал на Intel 8088 (4,77 МГц) с 16 КиБ ОЗУ и графической картой MDA, которая могла отображать только текст. Это был потрясающий успех, было продано 40 000 единиц в день анонса. Некоторое время IBM оставалась единственным поставщиком так называемого «ПК».
Когда популярность компьютеров IBM перешагнула порог, открытость, которая способствовала успеху, стала помехой. В марте 1983 года Compaq представила «совместимый с IBM ПК» под названием «Compaq Portable». Вскоре после этого рынок ПК был наводнён клонами ПК. IBM попыталась внедрить новый стандарт, используя защищённую авторским правом шину MCA. Когда эти усилия потерпели неудачу, IBM фактически потеряла контроль над рынком.
![](https://habrastorage.org/webt/bo/cz/-m/bocz-mkopa_5kbpexzhmnzy4clk.png)
Архитектура
ПК от IBM были построены вокруг концепции «большого ядра» с чудовищным процессором, большим количеством оперативной памяти и всем, что клиент хотел купить в виде дополнительной карты. В 1991 году это дополнение включало графическую карту, которая может быть любой, от TGA, EGA, до последней VGA. То же самое касается аудио части с не менее чем четырьмя типами несовместимых выходов (Beeper, AdLib, SoundBlaster и Disney Sound Source).
Чтобы выпустить программное обеспечение для «IBM PC или Compatible», разработчики могли отображать только список «минимальных требований» и «рекомендуемой конфигурации» на игровой упаковке. Поддерживаемые процессор, оперативная память, графический адаптер и звуковые карты были перечислены там.
«Типичный» ПК 1991 года был бы чем-то на базе процессоре Intel 386 с частотой 16 МГц с 2 МиБ ОЗУ и аудиокартой AdLib. Как и в Atari ST, был контроллер DMA, который нельзя было использовать для Blit, поскольку он был предназначен для передачи данных с дискет/HDD.
![](https://habrastorage.org/webt/_j/ku/sk/_jkuskby58dw5icpx_djy6sxt_k.png)
Видео системы
С выпуска первого ПК в 1981 и по 1991 год было выпущено пять основных графических стандартов. MDA и CGA в основном вымерли, но все ещё существовала большая база старых TGA/EGA, которые ещё не были обновлены до VGA.
Акроним Полное наименование Год выпуска -------------------------------------------------------------- MDA Monochrome Display Adapter 1981 CGA Color Graphics Adapter 1981 TGA Tandy Graphics Adapter 1984 EGA Enhanced Graphics Adapter 1985 VGA Video Graphics Array 1987
Старшие поколения TGA/EGA использовали ужасную цветовую систему с 2-мя битами на канал (6 бит на цвет).
![]() |
![]() |
Последнее поколение VGA использовало гораздо более впечатляющую систему с 6 битами на канал (18 бит на пиксель).
![]() |
![]() |
Конфигурирование этих карт было ужасом по связке 300 регистров, которые все взаимодействовали друг с другом. К счастью, в BIOS компьютера была предусмотрена процедура настройки всего. В то время, в зависимости от графической карты, было доступно 19 режимов.
Режим Тип Разрешение Цвета RAM/VRAM маппинг VRAM (KiB) ------------------------------------------------------------------------------- 0h,1h MDA 360 x 400 16 B8000 16 2h,3h MDA 720 x 400 16 B8000 16 4h,5h CGA 320 x 200 4 B8000 16 6h CGA 640 x 200 2 B8000 16 7h MDA 720 x 400 2 B0000 16 8h TGA 160 x 200 B0000 64 9h TGA 320 x 200 16 B0000 64 Ah TGA 640 x 200 16 B0000 64 Bh --- --------- -- ----- -- Ch --- --------- -- ----- -- Dh EGA 320 x 200 16 A0000 128 Eh EGA 640 x 200 16 A0000 128 Fh EGA 640 x 350 2 A0000 128 10h EGA 640 x 350 16 A0000 128 11h VGA 640 x 480 2 A0000 256 12h VGA 640 x 480 16 A0000 256 13h VGA 320 x 200 256 A0000 256
Обратите внимание на три режима 320x200, по крайней мере, с 16 цветами, которые соответствуют требованиям VM Another World. Как мы увидим, это не совсем то, что в конечном итоге использовалось.
Графический адаптер Tandy
Удивительно, но графический режим, обозначенный как TGA, был представлен не корпорацией Tandy, а IBM. Когда крупная железячная компания выпустила свой «PCjr» 1984 года, нацеленный на рынок Apple II/Commodore 64, они воспользовались возможностью улучшить свою устаревшую CGA. Позднее в том же году корпорация Tandy выпустила «Tandy 1000» по более низкой цене с более лёгкой расширяемостью и более широкой совместимостью с ПК. Если вначале Tandy «охватила» графическую подсистему IBM, лучшие продажи позволили им «улучшить»[1] и в конечном итоге «затмить» имя PCjr.
Каждая версия MDA/CGA/EGA/VGA имела обратную совместимость, но TGA имеет три эксклюзивных режима: 8h, 9h и Ah. Самым интересным для «Another World», конечно же, является режим 9h 320х200 с 16 цветами. Этот режим был доступен только со специальным расширением VRAM (8x16КиБ) на 128 КиБ, так как это «режимы с высокой пропускной способностью»[2].
Графический слой режима 9h очень похож на Atari ST, который мы рассмотрели в прошлой статье.
Фреймбуферы размещаются в оперативной памяти, поскольку на этих машинах не было VRAM. Пиксели располагаются линейно в виде полубайтовых нибблов, кодирующих 4-битные индексы цвета[3].
![](https://habrastorage.org/webt/ce/_b/ob/ce_bobgkqej_z3w1nkvo0_f0coa.png)
Усовершенствованный графический адаптер
EGA и VGA очень похожи. Они могут быть настроены на 320x200 в режиме 16 цветов через режим 9h. Здесь есть VRAM, к которой напрямую обращается центральный процессор.
Кадровый буфер организован так же, как на Amiga, которую мы изучали в первой статье, за исключением того, что каждая битовая плоскость находится в выделенном блоке памяти. Есть четыре блока. В режиме 9h бит из каждого из четырёх блоков объединяется в ниббл, получая тем самым 4-битный индекс цвета.
Карты VGA имеют намного больше VRAM (256 КиБ как 4x64 КиБ), чем карты EGA (128 КиБ как 4x32 КиБ), что не имеет значения для Another World. VGA имеет более глубокие цвета (6 бит/канал против 2 бит/канал), что очень важно.
![](https://habrastorage.org/webt/bv/00/r-/bv00r-dlcn9yvgvbb1qto9x12zc.png)
![](https://habrastorage.org/webt/mf/uv/fk/mfuvfku2r_9wagt0eauzx21xpgm.png)
Обманчиво мощный
С точки зрения вычислительной мощности ПК намного превосходил Amiga и Atari ST, которые мы рассмотрели ранее. Проблемой для игр было очень медленное видео.
Система памяти никогда не была предназначена для анимации. Она была разработана с учётом электронных таблиц и обработки текста. Перемещение всех этих пикселей по шине занимало много времени. Более того, работа с битпланом была обременительной, особенно без сопроцессора, такого как Amiga Blitter. Возьмём для примера простую процедуру очистки экрана в режиме 9h.
char far * VGA = ( byte far *) 0xA0000000L ;
#define SC_MAPMASK 0x02
#define SC_INDEX 0x03c4
#define SC_DATA 0x03c5
void selectBank(uint_8 bank) {
outp(SC_INDEX , SC_MAPMASK );
outp(SC_DATA , 1 << bank );
}
void ClearScreen() {
for(int y =0 ; y < 200 ; y ++) {
for(int x =0; x < 160 ; x ++) {
selectBank(x % 4);
VGA[x + y * 200] = 0;
}
}
}
Даже на лучшем ПК 1991 года этот пример кода не мог пройти 5fps[4]. Это патологический пример, поскольку экран очищается слева направо. Однако даже при вертикальной очистке, чтобы избежать переключения блоков памяти, этот код всё равно будет работать только со скоростью 10 кадров в секунду[5].
void ClearScreen() {
for(int x =0; x < 160 ; x ++) {
selectBank (x % 4);
for(int y =0 ; y < 200 ; y ++) {
VGA[x + y * 200] = 0;
}
}
}
При разработке игр старались максимально избегать переключения блоков. Именно по этой причине Wolfenstein 3D рисовал всё, от стен до спрайтов, включая HUD, по вертикали, и даже тогда только 72% экрана обновлялось в каждом кадре, достигая 11 кадров в секунду на 386SX 16 МГц.
Another World на PC
Учитывая ограничения TGA/EGA/VGA, перенос Another World на ПК выглядел непростой задачей. Мало того, что вам приходилось сталкиваться с фрагментацией, вы также должны были создать движок, невероятно быстрый для удовлетворения требований.
Эта проблема встала перед Даниэлем Морэ, который заключил контракт с Delphine Software.
Эрик Шайи хотел, чтобы на всех портах частота кадров соответствовала версиям Atari и Amiga. Даже на слабом ПК с процессором 286 игра должна была работать со скоростью 24 кадра в секунду.
— Даниэль Морэ
Решение проблем с фрагментацией
Чтобы разобраться с фрагментацией графической и звуковой систем, Даниэль написал слой абстракции, основанный на указателях функций.
Было бы намного проще написать порт PC DOS на C. Но Эрик написал версию Atari ST и Amiga на 68000 asm. Я принял это как вызов и поставил себе целью сделать то же самое. В конце концов, виртуальная машина была на 100% написана на x86 asm.
— Даниэль Морэ
В 1991 году не было PnP. Чтобы настроить игру, пользователи должны были запустить текстовый инструмент CONFIG.EXE, чтобы детализировать свою периферию.
![]() |
![]() |
Параметры сохраняются в файле CONFIG.DAT. Когда запускается ANOTHER.EXE, он читает файл и назначает указатели функций в зависимости от графической и звуковой карт.
Работа с TGA
При работе с графической картой TGA особого выбора не было. Режим 9h обеспечивает 320x200 с 16 6-битными цветами. Автоматическое преобразование палитр из 4-битных цветов в 2-битные с помощью LSR привело к алиасингу. Решением было преобразовать все палитры вручную.
Визуально результат «особенный». Имейте в виду, что проблема здесь заключается не в количестве цветов (TGA имеет 16), а в глубине цвета.
![](https://habrastorage.org/webt/xo/y9/87/xoy987qiqzr5czokdeockahqvta.png)
![](https://habrastorage.org/webt/a6/dw/fb/a6dwfbbbkra_eazogjn67ndsdqi.png)
![](https://habrastorage.org/webt/hn/au/mm/hnaumms0qdkqodxuvl-zip0ucdc.png)
![](https://habrastorage.org/webt/ck/rb/up/ckrbupztdcg6brhgepi2eydbfdq.png)
![](https://habrastorage.org/webt/no/qy/xp/noqyxpfxr4by9f_nqfxbwqjicj8.png)
Результат может быть не всем по душе, но я не думаю, что можно было бы сделать гораздо больше с 6-битными цветами. Расположение данных похоже на Atari ST, что было рассмотрено ранее, и далее TGA обсуждаться не будет.
Работает с EGA
На графической карте EGA лучшим режимом был режим Dh. Используются те же палитры, что и для TGA, поскольку цвета EGA также кодируются в 6-битном формате. Остальное работает как VGA.
Работа с VGA
С графической картой VGA всё куда интересней. На первый взгляд казалось, что режим 13h дал бы лучшие визуальные эффекты за счёт 4 бит на пиксель. Но Даниэль обнаружил, что VGA-карта не работает как EGA в режиме Dh. Загрузка палитры не ожидала 6-битного цвета, но 18-битного, как в режиме 13h. Это позволило также работать в режиме Dh, не теряя места, но с теми же визуальными эффектами, что и на Amiga.
По этой причине игра также поставляется с палитрами Amiga (вместе с палитрами TGA/EGA).
TL;DR: TGA/EGA/VGA
Игра поставлялась с двумя наборами палитр. Первый с 6 битами на цвет для TGA/EGA и набор с Amiga для VGA. В TGA используется режим 9h. В EGA/VGA игра работает в режиме Dh.
DRAWN и FILL
Отрисовка полигонов выполняется как на Atari ST, полностью программно. Простой алгоритм Брезенхэма генерирует горизонтальные линии начальных и конечных координат пространства экрана. В результате возникла проблема заполнения этих строк достаточно быстро.
К счастью, в Париже был этот невероятный компьютерный книжный магазин под названием «Le monde en tique» с набором книг по программированию, которых вы не могли найти больше нигде во Франции. Я нашёл объяснение одной особенности EGA/VGA, и это очень помогло.
— Даниэль Морэ
Хитрость заключалась в использовании факта, что полигоны были одного цвета, стоило лишь поиграть с выбором блока памяти. Вместо записи в один блок за другим, маска блока может быть настроена для одновременной записи во все блоки.
![](https://habrastorage.org/webt/yr/i7/uy/yri7uyb7dytevztgaslcdzehihy.png)
Производительность зависит от выравнивания, но в лучшем случае этот трюк позволяет писать 4 байта вместо одного. Это приводило к установке восьми последовательных горизонтальных пикселей при записи одного байта.
Я не помню точных чисен, но отрисовка полигонов была ОХРЕНЕННО БЫСТРОЙ. С этим 8-кратным ускорением частота кадров оказалась намного выше цели в 24 кадра в секунду, которую мы для себя поставили.
— Даниэль Морэ
COPY
Последней частью головоломки было найти способ достаточно быстро выполнить опкод COPY FB. Поскольку фреймбуфер был записан в VRAM благодаря уловке с выбором групп памяти, единственным способом копирования, очевидно, было возвращение кадрового буфера из VRAM в RAM для хранения и записывать его обратно в VRAM по требованию.
Уловка для решения этой проблемы была задокументирована Майклом Абрашем в его статье «Mode X Marks the Latch»[6]. Дизайнеры EGA/VGA не были полными садистами. Чтобы справиться с гранулярностью битовых плоскостей, каждый блок имеет однобайтовый переключатель. «Запоминание» последнего прочитанного байта значительно упрощает построение битов.
Хитрость здесь в том, чтобы переставить переключатели, чтобы они использовались для чтения и записи четырёх байтов за раз.
![](https://habrastorage.org/webt/uy/jf/ce/uyjfcesqb9fdis883ilnfgojj9q.png)
Выбрав сохранение BKGD в VRAM вместе с двойными буферами, код операции COPY FB был реализован с 4-кратным ускорением.
Удивительные сложности со звуком
В этой серии статей аудио часть не обсуждалась, так как это была «решённая проблема» на большинстве платформ. Очевидно, с портом ПК DOS это предположение не подтвердилось.
Часть с EGA/VGA не была действительно сложной для написания, потому что это было в основном написание кода для заполнения строк одним цветом или копирование целых кадровых буферов из VRAM в VRAM. Как только вы узнаете, как работает EGA/VGA, это становится довольно легко реализовать.
Трудности возникли при работе с аудио. Музыка для Amiga была написана с помощью инструмента «Sound Tracker» с аудиосэмплами, воспроизводимыми на четырёх каналах. На Amiga и ST это было просто, потому что в этих машинах было всё необходимое. Но на ПК это была совсем другая история. У этих машин был «buzzer» по умолчанию, а у счастливчиков был AdLib, способный воспроизводить FM. Ни один из них не имел возможности PCM, как, например, Sound Blaster и Gravis UltraSound.
Чтобы решить эту проблему, мне пришлось изменить таймер IRQ (от 80 или 100 Гц до 8000 Гц, уже точно не помню). Это означало, что основная программа прерывалась 8000 раз в секунду, чтобы сделать что-то ещё. Это «что-то ещё» должно было быть как можно короче, иначе ПК зависнет. Цель состояла в том, чтобы заставить PC Buzzer или AdLib вибрировать на желаемой частоте для имитации PCM сэмплов.
Результат был далёк от оригинала. В любом случае это было лучше, чем вообще никакого звука.
— Даниэль Морэ
На заметку: в версии для ПК издатель Interplay жаловался на продолжительность игры (которая может быть закончена всего за 20 минут опытными игроками). Чтобы увеличить продолжительность, были добавлены новые уровни (уровней стало на 3 больше – 15)[7].
Итог
Даниэль создал великолепный порт для Delphine Software. Работая в том же разрешении, что и на Atari ST и Amiga (320x200 и 16 цветов), ему даже удалось снизить минимальную конфигурацию до Intel 286 с 10MHz ЦП и 640 КиБ ОЗУ на ЛЮБОЙ графической карте: TGA, EGA или VGA[8].
Ссылки
- Tandy Graphics Adapter Incompatibilities.
- TGA has 3 rows of 8 64kx4 DRAM. The four is the 128k upgrade.
- IBM PCjr Technical Reference.
- Game Engine Black Book: Wolfenstein 3D clearScreen.
- Game Engine Black Book: Wolfenstein 3D p 127.
- Mode X Marks the Latch
- Another World, a.k.a. Out of this World — Versions of a Classic.
- Mobygames, Another World DOS Box.