Обзор графической архитектуры 3DO Interactive Multiplayer

3DO — консоль опередившая своё время. У нас она слабо известна да и конкурентную борьбу она быстро проиграла.
Тем не менее замечательна она тем, что вышла первой в пятом поколении — первой посягнула на рубежи полноценного 3D. Однако при этом это самое 3D в ней из–за молодости индустрии было реализовано весьма кривобоким образом, ныне вымершим.
Так же интересна консоль была еще несколькими моментами. Подробно можно прочитать на вики. Но я и тут сделаю краткий очерк.





Во первых — правообладатель консоли, The 3DO Company, не имел собственных мощностей и связей, поэтому разработав спецификацию железа предложил всем желающим производить его за лицензионные отчисления. Из-за такого подхода производители железа не могли продавать консоль себе в убыток, чтобы отбивать прибыль на продаже игр — поэтому и цены на консоль получились кусачими и она быстро покинула рынок.
Всего было три активных производителя консоли, из которых Panasonic стал наиболее часто с ней ассоциироваться, поэтому её нередко неправильно называют Panasonic 3DO. На самом деле Panasonic 3DO — это лишь конкретная и только одна из реализаций общей технологической спецификации 3DO Interactive Multiplayer.

Вышла первая консоль в США в сентябре 1993 года — то есть за пару месяцев до релиза Doom 1.
Так что окунёмся на несколько минут в графические реалии 3DO, посмотрим что это был за зверь.

ЦП

Центральным процессором (ЦП) в 3DO был 32–битный ARM (ядро ARM60, семейство ARM6, архитектура ARMv3) на частоте 12,5 МГц. Это еще без кэша и многостадийных конвейеров. Для сравнения говорится, например, что он обладает эквивалентной производительностью Motorola 68k на частоте 25 МГц (конкретно — 68030, то есть уже с 32–битным АЛУ).
Система обладает 2 Мб основной RAM и 1 Мб Video RAM (VRAM). Как минимум VRAM доступна одновременно и ЦП и видеочипу. Но вообще в документации как то вообще не делается упора на ограничения где должны лежать данные для Cel Engine, так что складывается ощущение, что VRAM привилегированна только по операциям SPORTS.
SPORTS это особое устройство и контроллер VRAM которое позволяет очень быстро поблочно её копировать или заполнять одинаковым значением. SPORTS работает только в пределах одной плашки VRAM в 1 Мб, если бы выходили расширения системы с несколькими мегабайтами VRAM, то документация чётко обозначает, что функции SPORTS способны копировать регионы только внутри блоков по 1 Мб.
Вообще, судя по документации, система явно проектировалась на вырост, много упоминаний, что та или иная программная функция в библиотеках еще не реализована — но когда–нибудь будет. А так же как раз отсылок к потенциальным разным конфигурациям и объёмам памяти (которых не случилось).
Программировать предлагается в рамках многозадачной ОС называемой Portfolio. В консоли кроме всего прочего есть 1 Мб ROM (и он далеко не пустой), так что видимо часть её сидит в там.
Так как в основном я читал документацию именно из Portfolio SDK ( скачать эту документацию можно тут: develop3do.narod.ru/index.files/devdocs.htm ), то сведений о том как именно устроено железо, его порты ввода–вывода и сообщение между компонентами в дальнейшем почти не будет. Только то, что важно с точки зрения SDK. Однако, кое какие любопытные особенности и это нам прекрасно показывает.

Дисплей

Видеобуфер для вывода на экран может иметь размеры 320x240 или 320x480 16–битных пикселя. Однако видеосигнал всегда выходит в разрешении 640x480 и цветности 8:8:8, причём каждый пиксель может отличаться от соседних. Так получается благодаря двум вещам:

1) Сложная система цветности:
16–битные пиксели привычно раскладываются на три 5–битных компоненты R, G и B, но эти компоненты в 3DO воспринимаются не сразу как интенсивности соответствующих каналов цвета, а как индексы из трёх независимых массивов из 32–ух 8–битных элементов из этих интенсивностей.
То есть это HiColor который индексирует покомпонентно TrueColor :) Всё еще осложняется тем, что если все 3 цветовых компоненты равны 0, то пиксель обрабатывается особым образом — его цвет берется из дополнительного 33–го слота этих же цветовых таблиц, а сам он опционально может стать прозрачным для оверлея заднего изображения на экране — это фича могла пригодится при наложении изображения на телевизионные вещи в телевизионных приставках, что заранее предусматривалось.
Причём этих таблиц RGB–интенсивностей в системе две — одна зашитая и неизменяемая просто перечисляет интенсивности с таким шагом чтобы линейно отобразить 5–битные индексы в 8–битные цвета, таким образом реализуя обычный HiColor.
Но есть еще другая — пользовательская, программируемая, причём возможности видеосистемы позволяют полностью переопределять её перед каждым сканлайном изображения, таким образом сильно раздвигая цветовую комбинаторику аппарата.
Плюс всё это еще осложняется тем, что неиспользованный бит в 16–битном пикселе (оставшийся после 5+5+5 индексов) может быть определен как раз под селектор палитры, раздвигая таким образом дипазон одновременно отображаемых цветов до 65536 штук и без манипуляций со сканлайнами.

2) Повышенная чёткость посредством «cornerweights»
Неиспользованный бит в пикселе таки не давал покоя и была придумана еще техника cornerweights — каждый из 320x240 логических пикселей разбивался по вертикали и горизонтали на 4 выходных пикселя–соседа (с итоговым разрешением 640x480) и один из этих соседей помечался как «основной». Основной пиксель отображался ровно цветом своего логического пикселя. А вот цвета его трёх соседей интерполировались с соседними логическими пикселями — причём сложным образом, чем ближе к ним были «основные» пиксели логических соседей, тем сильнее они оказывали влияния на итоговый цвет.
Для указания какой сосед из четырёх является основным нужно два бита, а «халявный» в пикселе был только один. Поэтому для полновесного «cornerweight» режима еще один бит отбирался у синей компоненты, она таким образом становилась 4–битной.
Кроме того возможны были варианты — значение одного из бит для cornerweight могло быть задано глобально как константа и тогда только второй бит брался из пикселя. В этом случае все цвета сохраняли свою битность, но «повышенная четкость» теряла в вариативности.

Суммируя вышесказанное можно наконец то описать видеорежимы 3DO — логическое разрешение экрана было 320x240 или 320x480 пикселей, но итоговая чёткость и цветность картинки могла разнообразится одним из четырёх вариантов:
1) Формат пикселя Wrrrrrgggggbbbbb — один бит задействован под cornerweight
2) Формат пикселя WrrrrrgggggbbbbW — два бита задействованы под полноценный cornerweight, синий канал лишён бита
3) Формат пикселя Prrrrrgggggbbbbb — один бит задействован под селектор палитры
4) Формат пикселя PrrrrrgggggbbbbW — один бит под cornerweight, еще один под селектор палитры и синий канал лишён бита

Лично мне кажется, что вся это возня и переусложнение сделаны совершенно напрасно. Тем более, что сама аппаратура консоли интерполирует цвета рассчитывая как раз на линейное соответствие индексов интенсивностям, то есть серьезные заигрывания с палитрами заранее обречены на отказ от каких то частей пайплайна.
Учитывая, что консоль вышла за три месяца до выхода легендарного Doom 1 (который, кстати, попадёт на консоль только тремя годами позднее и в ужасном качестве) в который все играли высунув язык и в 256–цветной палитре, то все эти потуги выдоить из «халявного» бита то больше цветности в HiColor, то какую то повышенную чёткость контуров — выглядят борьбой с ветряными мельницами.

Дисплейные списки

Еще одной «заморочкой» 3DO является то, что при выводе битмапа фреймбуфера на экран палитра и параметры повышенной чёткости могут меняться в каждой строке (сканлайне) изображения.
Начальная установка таковых параметров (для первого сканлайна) и далее их смена производится через дисплейные списки (VDL — Video Display List) — это структуры переменной длины от 5 до 38 слов (32–битных) в памяти, которые задают эти разнообразные параметры, количество сканлайнов которое данный VDL будет действовать и (опционально) указатель на следующий VDL к которому надо перейти после них.
VDL может содержать установку следующих параметров дисплея:
— адрес в видеопамяти, где находятся пиксели текущей строки (сканлайна) для вывода на экран
— параметры формата пикселя и значений по умолчанию для бит палитр и cornerweight
— содержимое таблицы пользовательской палитры (для задания всей таблицы палитры нужны 33 слова, что и диктует большую часть максимального размера VDL)
— размер текущего VDL (4 слова — минимум заголовка, плюс от 1 до 34 переменной части)
— количество сканлайнов после которых нужно переходить к следующему VDL (0, если этого делать больше не нужно)

В первом VDL обязательно должен быть задан адрес текущей строки пикселей в памяти, которую надо рисовать, в следующих же это не обязательно — за отсутствием смены будет рисоваться один большой фреймбуфер, адрес строки автоматически сдвигается с каждым сканлайном.
В принципе, если параметры дисплея не меняются в кадре, то одного затравочного VDL может быть достаточно — в нём надо будет выставить количество сканлайнов в 240 или 0.
В самом сложном случае можно сделать 240 разных VDL, связав их в список, выставив разную палитру и параметры отображения (и даже нацелить каждый на собственный сканлайн в памяти).
Однако больше смысла имеет организация с помощью VDL сложных схем двойной буферизации — например в видеопамяти можно завести три битмапа в 200, 200 и 40 строк. В последнем будет хранится редко меняющаяся панель информации, а в первых двух — два фреймбуфера для буферизированого сложного рендера.
При этом достаточно завести три VDL — в одном в качестве источника сканлайнов указывается первый битмап, во втором — второй и оба из них ссылаются на третий с 40 сканлайнами как на последний VDL в дисплейном списке. В чётных кадрам мы даём видеочипу указатель на первый VDL, а в нечётных — на второй, таким образом последние 40 строк экрана будут заполнены информацией из одного и того же буфера, а первые 200 — из двух разных, с буферизацией.

Cel Engine

Главное что в 3DO есть от «3D» — это конечно же растеризатор, или, как он тут называется — Cel Engine. Почему то фрагменты изображения растеризуемые им называются тут Cel–ами.
И что характерно — Cel–ы довольно сильно отклоняются от привычных нам ныне способов рендера и растеризации.
Растёт идея Cel Engine как бы из отрисовки обычной 2D–графики — главная его функция заключается в копировании прямоугольного куска изображения из некоего битмапа–источника в некий битмап–приёмник. Возможно они оба должны располагаться в VRAM, но это явно в документации не оговорено.
Давайте для начала рассмотрим какие возможности Cel Engine даёт для копирования прямоугольного куска изображения, то есть блиттинга обычного 2D–спрайта, а потом одним приёмом перейдём к 3D.
Итак, приёмник изображения должен быть прямолинейным битмапом в 16–битном формате, совпадающим с форматом экранного видеобуфера (хотя он необязательно должен с ним совпадать по адресам).
А вот с источником всё намного сложнее. Во первых битмап–источник может быть запакован. Неважен его внутренний формат, запаковать можно что угодно.
Паковка осуществляется техникой RLE — повторяющиеся N раз (особо выделены прозрачные) пиксели кодируются двумя байтами, не повторяющиеся — пакуются в полоски по N байт + байт заголовка, где N <= 32.
Во вторых — формат пикселей источника может быть довольно разнообразен. Это могут быть пиксели хранящие индексы в таблице 16–битных пикселей (1, 2, 4, 6, 8 и 16 бит) или прямо компоненты 16–битного пикселя (8 и 16 бит).
Форматы и того и другого замысловаты — есть возможность включать коэффициенты множителей в информацию о пикселе или так называемый P–бит, о чём ниже.
Итак, на этом этапе Cel Engine извлекает из битмапа–источника цвет и превращает его в 16–битный формат пикселя фреймбуфера.
А далее возможны варианты. Самый простой — это помещение полученного пикселя в битмап–приёмник.
Но данный этап Cel Engine может настраиваться более широко. В максимальном режиме он смешивает два пикселя через заданную формулу — таких формулы может быть задано две, одна из них является текущей, но если в пикселе источника задаётся P–бит, то он на лету может переключить текущий режим.
— Источником первого пикселя может быть или битмап–источник или произвольно заданный битмап в памяти, совпадающий по формату с битмапом–приёмником (чаще всего это он и есть).
— Источником второго пикселя могут быть те же вещи плюс еще постоянное, заданное значение цвета.
— Формула смешивания может умножать и делить RGB–значения в источниках на некоторый набор коэффициентов, далее вычитать их или суммировать между собой и опционально делить на два в конце. Стоит отметить, что Cel не допускает переполнения RGB–компонент.
Это всё даёт нам богатый спектр возможностей — от полупрозрачности до затенения. Причём заметьте — можно растеризовать битмап даже не делая его источником пикселей для смешивания. Это интересно ввиду того, что Cel Engine отбрасывает прозрачные пиксели источника еще до фазы пиксельного смешивания, не запуская её. Таким образом можно, например, выставить битмап сложной формы (в силу прозрачных пикселей) Cel–ом, но в процессе смешивания пикселей смешать приёмник с фиксированным цветом, таким образом затенив фрагмент во фреймбуфере. Если тут же нарисовать поверху уже обычным методом этот же Cel с небольшим смещением можно получить как бы картинку с тенью под ней.

А вот теперь начинаем потихоньку переходить собственно к обещанному 3D.

В самом простом режиме блиттинга Cel Engine переносит прямоугольный блок пикселей, но в сложном варианте, с помощью 6 коэффициентов с фиксированной запятой можно настроить произвольные афинно–перспективные трансформации, которые будут применяться к битмапу источника при растеризации.
Наглядно это можно себе представить как произвольную возможность задавать вершины четырёхугольника назначения в битмапе–приёмнике.
Лучше один раз посмотреть на картинку, чтобы понять:



В центре изображен «прямоугольный» перенос, самый простой и быстрый, по краям же изображено несколько примеров как можно произвольно «перетаскивать» и «перекручивать» углы уже четырёхугольника в битмапе–приёмнике.
Во главе всего по прежнему стоит прямоугольник. При этом важно заметить, что его координаты в источнике могут быть только прямоугольником с выровненными по осям сторонами — здесь нет аналогии с текстурными координатами в привычных ныне методах растеризации полигонов.
Вообще сам алгоритм растеризации тут «вырвернут наизнанку». Это можно было заметить уже по тому, что битмап источника может быть запакован.
На самом деле что здесь всегда происходит — Cel Engine линейно слева–направо, сверху–вниз обходит по порядку пиксели битмапа–источника и проецирует их в битмап–приёмник.
Не наоборот, как делают современные рендеры, которые пляшут от пикселей треугольника спроецированного уже на фрембуфер — выполняя пиксельные шейдеры и текстурные выборки по одному разу для каждого пикселя во фреймбуфере.
Cel Engine в 3DO пляшет от пикселей источника и проецирует их один за одним в приёмник — эта процедура выполняется ровно 1 раз для каждого (непрозрачного) пикселя в источнике.
Этому есть еще два свидетельства — во первых в FAQ по быстродействию прямо говорится, что уменьшение картинки при растеризации не ускоряет значительно рендер. То есть копирование картинки без изменения размера и копирование картинки с уменьшением размера во фреймбуфере хоть до 1 пикселя занимает почти что одинаковое время!
Второй момент касается увеличения картинки при масштабировании — существует флаг «быстрого копирования», который может приемлемо себя повести если картинка сохраняет размеры или уменьшается, но даст пропуски (вплоть до гигантских) между пикселями, если картинка увеличивается. Это может быть использовано даже как спецэффект. На деле документация прямо говорит, что при масштабировании с увеличением Cel Engine тщательно анализирует блоки пикселей в приёмнике которые надо залить одним и тем же пикселем источника и запускает для них двойной цикл этой заливки — это замедляет процедуры и именно это поведение и отключает флаг «быстрого копирования».
Еще один момент, связанный с поддержкой 3D есть в том, что консоль понимает порядок отрисовки «по часовой» и «против часовой», может отбрасывать отрисовку того или иного, причём корректно обрабатывая смену направления при самопересечении четырёхугольника.
Но больше никакой поддержки 3D в 3DO нет — ни Z–буфера, ни ускорения обработки вершин перед растеризацией, ничего иного больше нет. Всё что аппаратная начинка нам предлагает — это произвольно перекрученные прямоугольники.

Заключение

Вот такой «допотопный» и я бы даже сказал, что неопытный подход к рендеру был у 3DO. Как видно он явно растёт из блиттинга изображений, далее видимо пройдя через блиттинг с масштабированием и вращением эволюционировал в нечто с 3D–потенциалом, но с ограниченными возможностями в плане выбора текстурных координат. Всевозможные «подрагивания» уголков полигонов и подобные пиксельные неаккуратности были здесь частным гостем.
Вообще консоль действительно оставляет чёткое послевкусие неопытности: то борьбы с ветряными мельницами, то отсутствия понимания в какую сторону надо было двигать 3D–рендер.
Playstation 1 была объективно лучше, современнее и адекватнее потребностям рынка, на что ей хватило год и пары месяцев форы.

2 комментария

avatar
Про лицензионную политику же надо было досказать. С одной стороны, консоль лицензировалась сторонним производителям, и потому стоила дорого. Но с другой стороны, выход на платформу производителям софта обходился значительно дешевле других консолей, всего $3 за копию. Правда в итоге это привело к тому, что на не самой сильной платформе вышла куча треша от не самых сильных производителей.

Я пробовал писать под этот аппарат, ничего серьёзного. У меня сложилось впечатление, что делался он ещё до того, как возникло понимание перспективности 3D, больше под 'мультимедиа'. SDK там не предполагает работу с низким уровнем, но сам он создаёт впечатление очень проработанной системы, по крайней мере в сравнении с другими консолями контраст значительный (что несложно, у большей части предшественников вообще никакого SDK и документации, у последующих PS1 и N64 с этим также не фонтан). Железо, конечно, медленнное. Там даже два растеризатора (которые corner engine), но один по умолчанию почему-то выключен. Если включить, рендер в теории может ускориться до двух раз. Ещё запомнился трюк с ускорением доступа к данным на CD — они там могут дублироваться несколько раз в разных местах диска, время экономится за счёт позиционирования головки на ближайшую копию.
  • Shiru
  • +4
avatar
Гипотетическое демо под сабж, нерелизенное и неизвестно, доделанное ли хоть до какого-то состояния.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.