Обзор графической архитектуры SNES (+сравнение с Sega Mega Drive)

У нас битву 16–битных консолей выиграла спираченная Sega Mega Drive, в то время как в Северной Америке и Европе перевес оказался у Super Nintendo Entertaiment System (SNES), продолжателя дела Famicom известной у нас как Dendy. При этом, если в европах конкуренция была жаркой, то в пост-СССР SNES присутствовал на рынке очень слабо (в силу лицензионности), поэтому особо жарки споры о том какая из двух консолей круче всё–таки на западе, но у нас они тоже нередко встречаются.

Сразу хотел бы заметить, что с точки зрения программирования консоль от Сеги просто в разы проще и из-за этого она выигрывает приз моих программистских симпатий. Её процессор Motorola 68k по архитектуре был 32–битным, 16–битным в нём было только арифметико–логическое устройство (прозрачно для программиста). Он был проще и гибче в программировании нежели истинно 16–битный Ricoh 5A22, наследник 8–битного MOS 6502, используемый в SNES. Видеочип архитектурно тоже был простым и понятным, однако это означало и меньшие его возможности. Подробно о видеочипе Sega Mega Drive я писал тут.

Теперь же опишу видеочип SNES.

Палитра у SNES состоит из 256 элементов в RGB формате 5:5:5, поэтому доступно 32К оттенков и 256 цветов одновременно на экране, но может быть и больше за счёт direct color mode, о котором ниже. Это заметно больше, чем у Mega Drive.

Основная видеопамять в 64Кб так же размещается в видеочипе и доступна центральному процессору только через порты ввода–вывода или DMA. Так же как и мегадрайве есть другие банки видеопамяти, например палитра и там и там хранится в отдельном таком блоке. На SNES так же в отдельный банк памяти выделены описания спрайтов, OAM = object attrubite memory, (у мегадрайва они хранились в основной VRAM) в количестве 128 слотов. Спрайты (как и на мегадрайве) всегда 16–цветные (формат тайлов такой же как и у 16–цветных фонов и будет описан в разделе про них) и дотягиваются до большего числа цветов через селектор палитры в каждой из них — что расширяет количество цветов отображаемых в разных спрайтах одновременно на экране до 128 штук — и это верхняя часть палитры, она как бы разбита на 8 субпалитр.

Слоты спрайтов в OAM 4–байтные, в то время как на мегадрайве они 8–байтные, что оставляет многие биты слотов неиспользованными. В SNES же все биты просто не влезли! В результате и информации на один спрайт хранится меньше и с теми двумя битами на спрайт, что не влезли в основной слот OAM сделали полухак — их упаковали в 32 байта после основного массива OAM и разместили сразу за ним. То есть в OAM хранится 512 байт основного массива по 4 байта на элемент и сразу за ним — 32 байта упакованных по 2 бита на спрайт. При этом один из этих бит — это верхний бит координаты X спрайта.

Но это еще не всё — на сеге каждый спрайт мог варьироваться в размерах независимо по каждой из осей от 1 до 4 тайлов. На SNES спрайты тоже могут варьироваться в размере уже кратными тайлу порциями — 1, 2, 4 и 8 штук, вроде бы больше даже возможностей — но в описания спрайтов влез всего 1 бит касающийся размера — поэтому одновременно на экране разные спрайты могут иметь на выбор только один из двух заранее заданных размеров — первый или второй. А что именно это за размеры выбирается в регистрах видеоконтроллера. В одном кадре просто не может быть более двух разных размеров спрайтов, что не очень весело.
Таким образом, хотя и в сеге всего 80 спрайтов может быть на экране против 128 спрайтов у SNES, но распорядится их размерами она может более рационально. Если у сеги нужные к отрисовке спрайты соединяются в связный список, то у SNES опять таки нет на ни одного лишнего бита — спрайты просто рисуются все и всегда, ненужные просто надо выводить координатами за край экрана (как и в NES).

Так что по спрайтам SNES если и выигрывает, то незначительно (если вообще не проигрывает).
Но вот на задних фонах (слоях) SNES вырывается вперед.
Во первых — самих слоёв может быть до 4–х штук (в мегадрайве только 2).
Во вторых слои могут быть разной цветности: 4, 16 и 256 цвета (2, 4 и 8 бит на пиксель соответственно).
Состав и битность слоёв определяется текущим видеорежимом, которых может быть 8 штук, их можно составить в таблицу:

Режим    Бит/слой  OPT
         1 2 3 4      
-=-------=-=-=-=----=--
 0       2 2 2 2    -
 1       4 4 2      -
 2       4 4        +
 3       8 4        -
 4       8 2        +
 5       4 2        -
 6       4          +
 7       8          -

Следует помнить, что битность слоя — это битность его тайлов, но в самом слое в его (2–х байтных) плитках хранится как номер тайла, так и 3–битный селектор палитры, поэтому, например, в разных плитках 16–цветного слоя может отображаться до 128 разных цветов (это уже первые 128 элементов палитры). Не более 16 цветов может быть отображено лишь в одной плитке. Это было справедливо и для мегадрайва — только там было всего 4 субпалитры (с 2–битным селектором) и соответственно 64 цвета — одни и те же и на фоны и на спрайты.
Тайлы в SNES так же имеют базовый размер 8x8 пикселей, но каждый из слоёв может быть переведен в режим «тайлы 16x16», при этом он в каждой плитке соединяет 4 соседних тайла из таблицы тайлов (за базовый, чей номер указывается, берется верхний–левый).
Т.к. цветности тайлов у разных слоёв могут быть разные, то и таблицы тайлов у них тоже разуемеется могут быть разные — поэтому для каждого слоя отдельно можно выбрать базис в VRAM где начинается его таблица тайлов. В одном слое при этом может быть отображено максимум 1024 разных тайла, т.к. номер тайла в плитке является 10–битным числом (в мегадрайве — 11–битным).
Каждому фону так же задаётся где в VRAM хранится массив плиток, что он отображает. Они могут иметь размерности 32x32, 64x32, 32x64 и 64x64. В норме это даёт виртуальные размеры фонов как максимум — 512 пикселей по тем или иным осям, но если включить у фона режим «плитка 16x16», то максимальный размер плиточного фона в пикселях увеличивается до 1024x1024.
В режимах, где в колонке «OPT» стоит "+" есть интересная опция — Offset–Per–Tile — потайловое смещение. Эта штука возможно навеяна построчно–колоночными прокрутками из Мегадрайва. Оно работает очень похожим образом — величины прокруток указываются пораздельно, но уже пораздельно для каждой плитки экрана! При этом эти смещения записываются в плитки первого по таблице неотображаемого фона — он начинает использоваться как данные для прокрутки.
Эффект этот довольно мощный, комбинируя и модифицируя двумерный массив прокруток синусоидальными полями можно добиваться весьма впечатлящего «колыхания» поля, например как в игре Yoshi's Island (начинается с момента 4:05):

Однако Yoshi's Island была замечена в использовании чипа расширения Super FX GSU–2 и возможно как раз этот чип вносил посильную помощь в обновление такой таблицы.

Теперь сразу выскажу все прочие полезные SFX, которые в видеоконтроллере были:
— Два «окна» — две пары вертикальных границ лево–право которые могли наложить эффект просветления/затенения или замены цвета в своих границах. Подменой их параметров в каждой строке можно было добится любых сложных форм — так например делается голливудский эффект «That's all folks!», когда картинка исчезает в уменьшающемся кружке, окруженном чёрной заливкой.
— Direct Color Mode — для фонов с 256 цветами можно было включить режим «Direct Color Mode» в этом режиме цвета в каждой плитке формировали RGB–значения по формуле: RRRr0:GGGg0:BBb00, где RGB компоненты брались из пикселя тайла, а rgb–компоненты являлись битами селектора палитры данной плитки. Это потенциально расширяло пространство цветов одного фона до 2048 цветов одновременно на экране, но как видно обращаться с этим было несколько муторно.
— Мозаика — все фоны и/или спрайты могли «покрываться квадратиками», как бы теряя детализацию кратно пикселям, эффект на мой взгляд довольно бестолковый, но его нередко можно было встретить в играх при смене уровня
— Color Math — попиксельные цветовые эффекты, чаще всего применялись для эффектов полупрозрачности или сложного затенения. любой из фонов как и слой спрайтов можно «приписать» в одной из двух сущностей — main screen или sub screen. Отображается на экране обычным образом main screen. Но можно было на выбор активировать одну из несколько заранее заготовленных формул того как цвет (покомпонентно как RGB) main screen может взаимодействовать с цветом полученным из sub screen — в том числе, среднее арифметическое, например, что даёт нам эффект полупрозрачности. есть еще сложения/вычитание с насыщением и т.п.

Еще одна весьма полезная фича (о которой мне рассказал в комментариях на этом сайте ранее уважаемый Shiru) — это способность любых из восьми DMA-каналов SNES подкармливать порты ввода-вывода видеочипа порциями данных в специальном формате автоматически по наступлению прерывания HBlank. Это позволяет очень гибко и без участия процессора выполнять много техник обычно реализуемых перехватом прерывания HBlank центральным процессором без его участия. Например в Sega Mega Drive способность каждой линии фона иметь разную прокрутку — это захардкоженная в чипе способность, в SNES же такое можно реализовать как частный случай программирования этих DMA-каналов — просто на каждом HBlank избранный канал будет записывать в порт фона новое значение прокрутки. Гибко, мощно и элегантно, хотя и есть ограничение на общий размер данных который можно за один HBlank заслать в видеопорты.

А вот раскладка содержимого тайлов в памяти у SNES намного более замороченная. Если у Мегадрайва 16–цветные тайлы 8x8 хранятся довольно компактно и просто — 4 бита на пиксель, по байту на каждые 2 пикселя строки, 4 байта на строку и 8 строк — всего 32 байта.
То вот у SNES с этим всё сложнее.
Начнём с 4–цветных тайлов: у них 2 бита на пиксель, таким образом нужно 16 байт чтобы описать тайл 8x8. Но в первом байте хранятся первые биты каждого пикселя первой строки — 8 штук, а во втором байте — вторые их биты. Таким образом каждую строку из 8 пикселей описывают 2 подряд идущих байта — первый хранит нижние биты каждого пикселя, а второй — верхние. Это называется перемежающиеся слои.
Наращивание же битности происходит так: всякий раз удваивая битность мы просто берем формат предыдущей битности и добавляем к нему точно такой же слой сразу после него, таким образом удваивая количество бит вводом нового слоя.
То есть 16–цветные тайлы образованы как бы двумя подряд идущими 4–цветным тайлами, чьи соответствующие биты пикселей склеиваются. То есть в первом байте хранятся первые биты первых 8 пикселей, во втором байте — вторые их биты, а в 17–ом и 18–ом — третьи и четвертые соответственно.
256–цветные режимы (кроме Mode 7) соответственно повторяют два раза друг за другом тайловую информацию 16–цветных, таким образом количество байт по которым размазаны биты одного пикселя достигает восьми, причём их расположение не линейно.
В принципе для истинно тайловых видеоигр (которых было подавляющее большинство) это не особо важно — тайлы просто байт за байтом копируются из ПЗУ картриджа в видеопамять и как они там внутри устроены для игры неважно. Но для особо сложных эффектов вовлекающих динамический рендер в тайлы такое положение вещей весьма неудобно.

Отдельным особняком стоит Mode 7 — в нём все первые 32 Кб VRAM отдаются под единственный 256–цветный слой, причём в них хранятся и изображения тайлов и сама тайловая карта, имеющая уже размер 128x128 тайлов.
При этом плитки становятся однобайтными (во всех других видеорежимах одни 2–байтные, чтобы хранить 10–битный индекс тайла, селектор палитры и биты зеркалирования по вертикали и горизонтали), что требует 128x128=16384 байт VRAM, а тайлов таким образом максимально можно адресовать всего 256. Учитывая что на 8–битный тайл 8x8 требуется 64 байта, то 256 тайлов занимают 16Кб — как раз вторую половину из выделенных 32Кб.
Данные на этот раз хранятся абсолютно линейно — однобайтные пиксели всех тайлов следуют друг за другом ровно строка за строкой, будучи «упакованными» в байт–на–пиксель, так и плитки фона образуют двумерный массив 128x128, однако оба этих массива данных побайтово перемежаются друг с другом. То есть каждый четный байт памяти отведен под одно, а каждый нечетный — под другое! В целом всё линейно кроме этого — адреса всех байт одного массива умножены на два, а другого не только умножены, но и увеличены на 1. Почему так — скорее всего дело тут в том, что с точки зрения аппаратуры четные и нечетные байты VRAM разведены в разные банки памяти для ускорения линейного считывания слов — это старый как микросхема трюк. Поэтому видимо видеочип при такой организации памяти может параллельно работать с данными тайлов и с массивом плиток без помех.
Но программист тут опять вынужден мириться — дело в том, что любой доступ к VRAM (это, кстати, справедливо и для мегадрайва) извне видеочипа (например процессором) происходит только 16–битными словами. Это значит, что для того чтобы изменить только один байт в VRAM надо считать слово по данному адресу, изменить в нём байт и записать обратно. Понятно, что при всём вышесказанном это превращается в дополнительный геморрой.
Подробно о легендарном Mode 7 я писал в другой статье тут.

Подводя итоги

У видеочипа SNES объективно лучше палитра, объективно больше спец–эффектов — всё что у сеги есть — это построчные и постолбцовые прокрутки фонов и просветления/затенения определенных плиток.
SNES же богат на потайловый скроллинг, мозаичный эффект, обрезку по плавающим двум границам двух «окон», direct color mode и попиксельный Color Math, который позволяет реализовать частичные затенения/осветления и полупрозрачность.
Несомненно жемчужина SNES — это Mode 7.

Дальше всё не так уж однозначно — спрайтов вроде бы и больше, но их возможности усечённее. Фонов больше и их цветность разнообразнее, но не во всех комбинациях, плюс несколько портит впечатление сложность и слабая пригодность раскладки тайлов для динамического рендера.

Так или иначе, но по итогу возможности видеочипа SNES богаче, проигрывает эта консоль сеге только по процессору, зато и основной памяти больше (128Кб против 64Кб) и звуковой чип мощнее (у сеги был звуковой чип FM–синтеза в то время как у SNES более совершенный чип с программируемыми банками звуковых данных).

Поэтому по сумме очков SNES одерживает безоговорочную победу.

Есть еще один забавный факт, о котором хотелось бы упомянуть — что у видеочипа Mega Drive, что у видеочипа SNES присутствует немало бит в регистрах, которые позволяют те или иные фоны или таблицы тайлов отображать в другие 64Кб VRAM. То есть чипы изначально проектировались под 128Кб VRAM с возможностью отображать в верхние 64Кб или иные вещи. Например тайлы спрайтов можно хранить в одном банке, а тайлы фонов в другом и так далее.
Таким образом, очевидно, что эти же видеочипы видимо использовались где–то еще — в аркадных автоматах как минимум, уже с полной мощью 128–килобайтного VRAM.

0 комментариев

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.