Войти
ФлеймФорумЖелезо

Блеск и нищета 8/16-битных консолей и ПК (34 стр)

Страницы: 133 34 35 3639 Следующая »
#495
13:42, 12 янв. 2019

Кстати, как ни странно, но такие игры как, например Warcraft 1, еще на DOS, на машинах своего времени нередко тоже "чиркали" по грани возможного в плане вывода графики, хотя казалось бы - чего такого, ложи в софтваре спрайты в буфер и делов то. А вот таки да - в то время машины едва с этим справлялись с приемлемым фпс.
Даже много лет спустя написав софтверный блиттер в досе для Mode 13 (320x200) на уже на порядки более быстродейственном Pentium я сильно удивился, что филлрейт то не радовал, не улетал в космос даже на пентиуме, который рвал 386-ые как бог черепаху, то есть на 386-ых варик вообще на грани возможного работал.


#496
(Правка: 14 янв. 2019, 8:48) 7:37, 13 янв. 2019

Гы, сделал по схеме LDPUSH из комментов про Old Tower и GULF выше вертикальный скроллинг двух верхних третей экрана на спектруме.
То есть заводится вспомогательный теневой буфер размером чуть больше 8 Кб описываемый в ассемблере следующим образом:

back_buf  dup 128 ; всё до последнего edup будет повторятся 128 раз
    ld sp, xxxx
    dup 16  ; всё до следующего edup будет повторятся 16 раз
    ld de, $ ; $ - это текущий адрес памяти для теста
    push de
    edup
    edup
    jp back_buf
Т.е. массив из подряд идущих 128 строк где первые три байта заняты инструкцией загрузки в SP константы - байта следующего за концом текущей строки пикселей на экране спектрума, а далее 16 раз повторяется загрузка констант в DE с помещением его в стек (суммарная длина последовательности из этих двух инструкций - четыре байта, что в два раза больше полезных данных помещаемых при этом на экран). В конце всего этого безобразия прыжок на начало для закольцовывания.
Изначально загрузки sp заполнены так, чтобы первая линия инструкций закрашивала первую строку пикселей на экране, вторая - вторую и так далее. Те кто помнит какая нелинейная у спектрума раскладка знают почему sp надо на каждой строке загружать новой базой.

Но инструкции закольцованы (и не просто так), поэтому код вызывающий их производит модификацию кода и заменяет код первой инструкции LD, SP... на инструкцию JP (HL), а сам, заполнив SP из непосредственных данных только что пропатченной инструкции, прыгает на эффективный кусок LD DE..., который уже дальше как с горки катится по строкам заполняя экран и в конце закольцовываясь через JP back_buf оказывается как раз на инструкции JP (HL) и возвращается в вызывающий код, т.к. HL бережно заполнен адресом возврата.
А по адресу возврата располагается код, который возвращает SP на настоящий кадр стека, и откатывает патчинг возвращая на место код инструкции LD SP...

Зачем так сложно? Потому что далее мы можем сделать следующее - сдвинуть все непосредственные данные в инструкциях LD SP... в кольце (128 раз) так, что строки поменяют циклично свою привязку к строкам пикселей на экране и текущей строкой (которая патчится и куда происходит переход) делать не первую, а вторую.
Таким образом переписав в памяти всего 128*2=256 байт (затравочные значения SP) и один код инструкции мы осуществляем скроллинг целых двух третей экрана.

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

Сказано - сделано, написано - затестировано. Код просто бесконечно скроллящий вертикально первые 2 трети экрана работает с FPS ~128. То есть быстрее, чем 60 герц в два раза. :D

Правда в игре с вертикальным скроллингом надо делать наоборот - вытягивать теневой буфер в высоту и потом уже тратить освободившееся время на спрайты и прочее.

+ если интересен код...
#497
8:23, 13 янв. 2019

А зачем патчить код? Рочему бы не делать вызов по указателю? Или спектрумовский процессор такого не может?

#498
8:45, 13 янв. 2019

Panzerschrek[CN]
> Рочему бы не делать вызов по указателю?

Дело в том, что это инструкция JP (HL), а HL уже занят под возврат в вызывающий код как раз для краткости этой же однобайтовой инструкцией, поэтому одно другому начинает мешать и проще патчить JP START_ADDR.
Это как раз вот этот фрагмент кода:

...
    inc hl                  ; hl = адрес куда надо перейти в буфер
    ex de, hl    ; de <-> hl
    
    di      ; запрещаем прерывания
    ld sp, hl    ; sp = затравочное для текущей строки
    ex de, hl    ; de <-> hl (восстанавливаем в hl адрес перехода)
    ld (.jumper+1), hl  ; устанавливаем распрыжку на текущую строку
    ld hl, .raster_end  ; запоминаем в hl адрес возврата из бэкбуфера

.jumper    jp 0      ; адрес в распрыжке обновляется кодом выше
#499
(Правка: 14:32) 14:31, 13 янв. 2019

Кстати, никогда не мог понять почему в Zilog решили в мнемонике JP (HL) записывать HL в круглых скобках.
Везде в их синтаксисе круглые скобки были признаком индирекции.
Метки всегда были только числовыми значениями адресов к которым метки были прикреплены.
Так ld hl, label помещало в hl именно адрес за которым закреплена метка, её числовое значение. Т.е. просто помещение в регистр константы. В терминах ассемблера Intel это было бы mov eax, offset label, что, как по мне, запутывает.
ld hl, (label) же у Z80 загружает в hl значение из памяти по адресу label (в терминах Intel это mov eax, label). И всегда когда нужно загрузить из адреса - адрес окружается скобками. ld a, (hl) - то же самое, в аккумулятор грузится байт по адресу hl.
Но какого чёрта JP (HL) записывается как через индирекцию, хотя совершаемое действие в точности соответствует ld pc, hl - вот тут мне всегда было непонятно. Это полностью выбивается из схемы, ведь никогда не пишется JP (label) - нет такой команды вообще.

#500
21:41, 13 янв. 2019

Какие то консоли, даже в чём то опередили своё время.

История Virtual Boy

#501
7:34, 14 янв. 2019

KPG

Я когда покопался в вопросе, то даже ошалел.
3D-очки и виртуальность (только настоящие, а не как у виртуал боя) ныне преподносятся, как что-то только-только вылупившееся из яйца для потребительского рынка.
Но на самом деле еще во времена DOS были виртуальные решения для розничных покупателей, работающие и для Doom и Quake и так далее.
Более того - всевозможных фирм и их шлемов пытающихся окучить розничный рынок виртуальности с начала 90-х годов было не меньше десятка!
Не у всех правда было позиционирование, так что некоторые решения сводились к простой стереоскопии, но даже вон в том раннем шлеме под Doom можно было головой вертеть.
Проблем конечно было много - цена от штуки долларов и низкое разрешение, но они пытались.
Поэтому когда Oculus ворвался с обещаниями современного шлема за $300, то только в цене и качестве была новизна.

А Virtual Boy - это очень странная маркетинговая отрыжка.

#502
10:12, 14 янв. 2019

Упс, перепроверил на Spectaculator - на самом деле скроллер, который я описал выше даёт не ~128 фпс, а где то в два раза ниже - почему то Unreal Speccy на котором я проверял как бы разогнан в два раза. Ума не приложу почему.

#503
10:14, 14 янв. 2019

А FUSE что показывает?

#504
10:25, 14 янв. 2019

0iStalker
> А FUSE что показывает?

То же что и Spectaculator - примерно в 2 раза меньший фпс, чем было у UnrealSpeccy. Думаю, что в последнем просто включен режим турбо у Scorpion, это как раз ровно в 2 раза большая тактовая частота. Но в конфиге так вот сходу не могу найти этого, всё-таки там изрядная доля красноглазия в подходе к настройкам и GUI.

#505
14:50, 14 янв. 2019

Переделал код код так чтобы он проматывал в скроллируемой области содержимое памяти спектрума и чтобы можно было в коде настраивать ширину и высоту скроллируемого участка.

А так же по совету Дениса Грачёва - того самого автора Old Tower (и многих других игр на спектруме) - применил технику измерения временных промежутков с помощью синхронизации с прерыванием и покраской бордюра, так что по ходу луча прямо видно по высоте закрашенных зон бордюра сколько времени занимает тот или иной фрагмент кода и где в момент его выполнения находился луч электронно-лучевой трубки кинескопа. При этом код получается синхронизирован с VDraw (VSync=on) и пашет ровно 50 кадров в секунду, скроллинг абсолютно при этом плавный, без вертикальных разрывов - просто идеальный.

+ код

line_count - это как раз число строк скроллируемой области, а push_count - число push de, то есть число выводимых знакомест деленное на два.
поигрался параметрами и при line_count = 128 и push_count = 10 получается такая картинка:

Изображение

Всё это чинно и плавно плывёт вниз.
А вот теперь внимание на бордюр - первая сверху-вниз синяя зона по вертикали отсчитывает сколько времени в единицах отрисованных строк занимает вывод LD:PUSH-буфера на экран. Если соизмерить эту зону с зоной отрисовки, то видно, что вывод этот даже немного обгоняет ход луча.
Следующая белая зона бордюра измеряет сколько времени отнимает обновление констант в инструкциях LD SP, xxxx в LD:PUSH-буфере для следующего кадра. Весомо, хотя обновляется всего 256 (128*2) байт памяти (крутится в цикле). LD:PUSH за соизмеримое время успевает перебрасывать 2560 байт - в 10 раз больше!
Вот она - сила LD:PUSH!
Следующая крохотная синяя полоска - это фрагмент обновления верхней линии LD:PUSH-буфера - просто линейно заполняется новой порцией данных из указателя бегущего по памяти ПК.
Как видно здесь уже луч ЭЛТ находится ниже активной области прокрутки, а это значит, что в коде далее можно выводить в эту зону спрайты, не боясь создать мерцания изображения.
Более того - эти спрайты не надо стирать, ибо LD:PUSH всё перетирает каждый цикл начисто.
Т.е. в целом, можно в такой зоне сделать например top-down шутер с идеально плавной прокруткой.

#506
(Правка: 15:17) 15:17, 14 янв. 2019

P.S.
А хотя картинка немного сложнее.
Прерывание срабатывает не прямо на границе экрана, а как будто бы 64 строками выше первой строки экранного изображения (это ровно половина скроллируемой области на картинке выше), то есть над первой строкой экранной области есть еще как бы 64 строки закрашенных синим - их надо включать во время LD:PUSH.
Ну и после нижней строки экрана есть еще как бы 56 виртуальных строк "vblank" (хотя в vblank формально входят и 64 верхних "виртуальных" строки, но вот так генерируется прерывание). Имея это ввиду уже можно реально оценивать какие там есть пространства для манёвров.

#507
15:23, 14 янв. 2019

=A=L=X=
> Прерывание срабатывает не прямо на границе экрана

На отечественных клонах прерывание генерируется в 0й строке телевизионного растра  - это, как раз, в большистве случаев,  за 64 строки до первой строки фреймбуфера.  На фирменных машинах, ULA генерирует прерывание в 16й строке телевизионного растра.  Если у тебя эмулируется Пентагон/Скорпион, то таки да, 64-ю строками выше.

#508
15:45, 14 янв. 2019

0iStalker
> На фирменных машинах, ULA генерирует прерывание в 16й строке телевизионного растра.
Я вот тут смотрел: https://www.worldofspectrum.org/faq/reference/48kreference.htm

48K ZX Spectrum
...
After an interrupt occurs, 64 line times (14336 T states; see below for exact timings) pass before the first byte of the screen (16384) is displayed...

По идее любая машина не соблюдающая этого правила пролетает по всем ухищрениям с цветами типа того же раскрашенного бордюра или мультколора.
#509
15:59, 14 янв. 2019

=A=L=X=
> По идее любая машина не соблюдающая этого правила пролетает

И ведь пролетает, - http://zxpress.ru/article.php?id=11847

Страницы: 133 34 35 3639 Следующая »
ФлеймФорумЖелезо