Shaos wrote:Shaos wrote:
Я хочу сделать включаемую отдельно Спринтеровскую нарезку фреймбуфера квадратами 8х8 пикселов - чтобы это получилось, надо оценить скорость перенастройки DMA, которое сейчас делается один раз для каждой строки, а мне надо до 80 раз в пределах одной строки (чтобы поддержать не только линейные графические режимы Спринтера, но и текстовые). В худшем случае мне придётся сделать конвейер, при котором в тени будет готовиться новая строка из кусочков памяти, пока аппаратный рисовальщик будет рисовать текущую строку. Ну и кроме того я хочу прямо в железе сделать сплющивание 720-пиксельных 16-цветных режимов в 480 пикселов по алгоритму, который я описал чуть раньше (и уже реализовал программно). Спринтеровские описатели экранов и палитра (у бейджовского фреймбуфера она одна, но я знаю как поддержать 4 - надо просто сделать массив цветов палитр длиннее) будут находится внутри FPGA (что должно потребовать как раз порядка 40 килобайт).
На самом деле в текстовом режиме будет не 80 чтений в пределах одной строки, а 80 чтений по ДВА 32-битных слова (8 байт, чтобы вычитать букву из знакогенератора) в пределах горизонтального ряда квадратиков (8 строк), так что наверное надо будет конвеерно готовить цепочку квадратиков 8x8 разве что под это дело надо будет найти 480x8=3840 байт (причём дважды ибо конвеер). Однако для графических режимов всё-таки придётся вычитывать построчно, причём заранее подсчитав если видеопамять идёт линейно через несколько квадратов, то читать её надо за "один присест" одним DMA запросом. Усложняет задачу ещё и то, что теоретически текстовые и графические режимы могут перемешиваться и нужно уметь правильно настраивать DMA по ходу пьесы.
Другой сложный момент заключается в том, что например расположенная выше картинка (FN с запредельной рамкой-оконтовкой) на реальном Спринтере состоит из квадратиков разной цветности и разрешения - FN имеет высокое разрешение и 16-цветные пиксела, а рамка - низкое разрешение и 256-цветные пикселы (а в примере выше я просто привёл рамку к высокому разрешению и 16-цветам, чтобы не усложнять пример). Так как я предполагаю "сплющивать" высокое разрешение, а низкое оставлять "как есть", мне придётся отслеживать встречались ли в пределах кадра (по видимому прошлого) квадратики высокого разрешения и если был хотя бы один, то надо будет включать "сплюскивание" для квадратиков повышенной чёткости, а квадратики пониженной чёткости придётся "апскейлить", превращая каждые 3 пиксела в 4 (повторяя каждый третий пиксел 2 раза). Если же весь экран состоит из квадратиков пониженной чёткости (и повышенной цветности с 8-битными пикселами), то графика должна выводиться как есть (выдавая в пределе 448 пикселов в ширину - максимум того, что может себе позволить описатель экранов Спринтера, состоящий из 56 квадратиков по горизонтали).
Придумал алгоритм, который вот это всё будет учитывать на лету - вобщем у нас будет флаг global_hires, который устанавливается в 1 если в предыдущем кадре был хотя бы один квадратик высокой чёткости (16x8 16-цветных пикселов) - в начале следующего кадра устанавливаются начальные условия в зависимости от состояния этого флага:
Если global_hires=0, то мы имеем зацикленную в кольцо последовательность описателей 112 квадратиков начиная с номера 97, по которой мы будем двигаться с шагом 2 (это позволит иметь по горизонтали максимум 448 256-цветных пикселов - можно это назвать "суперзапредельным" режимом Спринтера, который невозможен на старом Спринтере), причём если по ходу рендеринга попадутся квадратики высокого разрешения, то они будут выведены неправильно в пределах этого кадра, однако после этого флаг global_hires будет установлен в 1, и следующий кадр будет показан правильно (в режиме высокой чёткости и со "сплюснутыми" пикселами).
Если global_hires=1, то мы стартуем с квадратика 107 и идём до квадратика 86 (после номера 111 будет идти номер 0), игнорируя квадратики с номерами от 87 до 106 (они будут за пределами видимого экрана) - в этом режиме надо пропустить первые 3 байта, т.е. из самого левого квадратика будут показаны только 5 256-цветных пикселов либо 10 16-цветных пикселов (в зависимости от битов режима в текущем квадратике и столько же мы потеряем с правого края), либо для простоты можно стартовать с самого левого пиксела, но тогда справа мы потеряем 16 16-цветных пикселов вместо 10 (т.к. при таком подходе можно показать только 720 "сплюснутых" пикселов из 736).
По ходу движения по квадратикам мы будем генерировать четвёрки 256-цветных пикселов (т.е. 1 байт на пиксел), которые можно назвать бинарно 00, 01, 10 и 11:
- Чтобы получить пиксел 00 мы просто копируем текущий пиксел источника как есть (там будет либо 1 полноцветный пиксел либо 2 16-цветных);
- Чтобы получить пиксел 01 мы смотрим на состояние флага global_hires и битов режима текущего квадратика:
- если global_hires=0 или текущий квадратик 256-цветный, то копируем текущий пиксел источника как есть (там будет один 256-цветный пиксел);
- если global_hires=1 и текущий квадратик 16-цветный, то в младший ниббл копируемого байта надо записать младший ниббл из предыдущего байта (тут может произойти путаница палитр, если они были разные у предыдущего и текущего байтов);
- Чтобы получить пиксел 10 мы смотрим на состояние флага global_hires, битов режима текущего квадратика и режим предыдущего пиксела (мы могли попасть на границу квадратиков):
- если global_hires=0 или текущий квадратик 256-цветный:
- если предыдущий пиксел тоже был 256-цветным, то копируем текущий пиксел источника как есть (там будет один 256-цветный пиксел);
- если предыдущий пиксел был 16-цветным, то копируем байт, составленный из младших нибблов предыдущего байта (с сохранением его палитры);
- если global_hires=1 и текущий квадратик 16-цветный:
- если предыдущий пиксел тоже был 16-цветным, то копируем байт, составленный из младшего ниббла предыдущего байта и старшего ниббла текущего байта (тут может произойти путаница палитр, если они были разные у предыдущего и текущего байтов);
- если предыдущий пиксел был 256-цветным, то копируем байт, составленный из старших нибблов текущего байта;
- если global_hires=1, то инкремент указателя источника в данном такте НЕ ПРОИЗВОДИТСЯ (т.е. мы в глобальном режиме высокой чёткости идём тройками байт источника, а при низкой чёткости - четвёрками)
- Чтобы получить пиксел 11 мы смотрим на состояние флага global_hires и битов режима текущего квадратика:
- если global_hires=0 или текущий квадратик 256-цветный, то копируем байт как есть;
- если global_hires=1 и текущий квадратик 16-цветный, то в копируемом байте переставляем нибблы местами;
Также при копировании номера палитры (0...63) вместе с байтом графики в режиме global_hires=1 надо будет обнулять старший бит номера палитры если текущий квадратик является 16-цветным (таким образом мы будем превращать 16-цветную палитру в комбинированную 256-цветную, которая будет заполняться программно в палитрах с номерами N-32) либо пока оставить номер палитры нетронутым, но тогда надо быть готовым, что заполнив 16-цветную палитру программно, мы будем читать обратно не те RGB значения, которые были туда записаны.
P.S. Чтобы не было перепутывания палитр на границах "сплюснутых" квадратиков в многопалитровых 16-цветных картинках надо делать смену палитр с шагом 48 16-цветных пикселов, либо делать так, чтобы в пикселах на границах квадратиков использовлись цвета, которые имеют одинаковые RGB значения в разных палитрах, либо чередовать 16-цветные квадратики с 256-цветными - в этом случае границы будут без цветных помех.