Карты VGA читают в пиксельном буфере, когда бит вертикального восстановления очищен? - PullRequest
0 голосов
/ 22 мая 2018

Я работаю над игрой для DOS, которая использует режим видео 13 ч.

У меня всегда были проблемы с разрывом экрана, но до сегодняшнего дня я игнорировал эту проблему.Я предполагал, что это будет проблемой, потому что это будет включать в себя задержку записи пикселей на некоторое точное время.Но это было действительно очень просто.

Все, что вам нужно сделать, - это дождаться, пока бит вертикальной трассировки (бит 3) байта состояния VGA, доступный на порту 0x3da в цветном режиме, будет вновь установлен.

Так что мне просто нужно было изменить эту старую процедуру, которая записывает мой кадровый буфер в буфер пикселей VGA, начиная с A000: 0000:

WRITE_FRAME PROC

;WRITES ALL 64,000 PIXELS (32,000 WORDS) IN THE FRAME BUFFER TO VIDEO MEMORY

    push es
    push di
    push ds
    push si
    push cx

    mov cx, frame
    mov ds, cx
    xor si, si             ;ds:si -> frame buffer (source)                  

    mov cx, vidMemSeg
    mov es, cx
    xor di, di             ;es:di -> video memory (destination)

    mov cx, (scrArea)/2    ;writing 32,000 words of pixels
    rep movsw              ;write the frame


    pop cx
    pop si
    pop ds
    pop di
    pop es
    ret

WRITE_FRAME ENDP

И вот измененная процедура, которая ожидаетБит вертикальной трассировки, который нужно установить заново:

WRITE_FRAME PROC

;WRITES ALL 64,000 PIXELS (32,000 WORDS) IN THE FRAME BUFFER TO VIDEO MEMORY

    push es
    push di
    push ds
    push si
    push ax
    push cx
    push dx

    mov cx, frame
    mov ds, cx
    xor si, si             ;ds:si -> frame buffer (source)                  

    mov cx, vidMemSeg
    mov es, cx
    xor di, di             ;es:di -> video memory (destination)

    mov cx, (scrArea)/2    ;writing 32,000 words of pixels

                           ;If vert. retrace bit is set, wait for it to clear
    mov dx, 3dah           ;dx <- VGA status register
VRET_SET:
    in al, dx              ;al <- status byte
    and al, 8              ;is bit 3 (vertical retrace bit) set
    jnz VRET_SET           ;If so, wait for it to clear

VRET_CLR:                  ;When it's cleared, wait for it to be set
    in al, dx
    and al, 8
    jz VRET_CLR            ;loop back till vert. retrace bit is newly set

    rep movsw              ;write the frame


    pop dx
    pop cx
    pop ax
    pop si
    pop ds
    pop di
    pop es
    ret

WRITE_FRAME ENDP 

Это не совсем идеально.Все еще есть небольшое дрожание, особенно когда фон позади спрайта прокручивается вверх или вниз, но смотреть на это больше не мешает.

Мой вопрос: почему это работает?

Я предполагаю, что когда установлен бит вертикального восстановления, пиксели уже считаны в память карты VGA, и в данный момент она записывает уже загруженные пиксели.Однако, когда бит вертикального восстановления очищен, он загружает пиксели из A000: 0000 в локальную память.Для этого он использует DMA, верно?

Итак, запись в A000: 0000 безопасна только тогда, когда VGA-карта записывает пиксели (бит установлен), а не загружает пиксели в (бит очищен)

Или я совершенно не прав?

1 Ответ

0 голосов
/ 22 мая 2018

Нет отдельного буфера, в который считывается карта VGA.(Помните, что когда VGA был новым, даже 32 КБ памяти DRAM были дорогими. Кроме того, пропускная способность памяти была низкой. Некоторые видеокарты использовали двухпортовую ОЗУ , поэтому доступ из ЦП не мешал сканированию; он может быть прочитан / записан на одном порту, когда CRTC / RAMDAC считывает данные пикселей.)

В течение интервала вертикального гашения видеокарта не читает или не записывает видеоОперативная память вообще;он существует, так что ЭЛТ может изменять напряжение отклоняющих пластин электронного луча назад к верхней части экрана, не рисуя линию вверх по экрану.Затем аппаратное обеспечение VGA начинает считывать видеопамять по порядку для следующего сканирования следующего кадра.

(Современное оборудование, конечно, не управляет ЭЛТ, но читает VRAM в порядке с "интервалом гашения""все еще вещь).


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

Если ваш код, который изменяет видеопамять, работает достаточно быстро, это делается до того, как аппаратное обеспечение снова начинает читать, так что вы не получите разрыв.(На самом деле, поскольку вы пишете экран в порядке сканирования, , он должен быть достаточно быстрым, чтобы опережать растровое сканирование , поэтому вывод на экран не передает memcpy и отображает некоторые«старые» пиксели позже в кадре.)

На старом оборудовании rep movsw было недостаточно быстрым для копирования целого кадра данных во время VBI, особенно при записи в ввод-вывод с отображением в памятьчерез автобус ISA.Вместо этого вы обычно двойной буфер , изменяя базу VGA, чтобы указывать на уже нарисованный кадр во время VBI.Таким образом, вы рисуете в одном буфере, в то время как другой сканируется, давая вам полный интервал кадров для его обновления, а не только VBI.


rep movsw работает очень быстрона современных современных процессорах (например, если вы загружаете современный компьютер в реальном режиме).Если VRAM отображается как WC (он же USWC: не кэшируемое спекулятивное объединение записи), то rep movsw будет копировать 16 или 32 байта за раз (режим Fast Strings или даже ERMSB (Enhanced Rep Mov / Stos B)), получая выгоду от записиобъединение буферов.(Обычные хранилища в памяти WC похожи на хранилища NT в обычной памяти WB (с обратной записью)).Ошибки Intel (, такие как IvyBridge BU2 ) указывают на то, что REP MOVS в памяти WC действительно работает следующим образом: если вы пересекаете страницу из WC в память UC, некоторые хранилища в память UC могут происходить с широкими хранилищами быстрой строкивместо отдельных 16-битных хранилищ за rep movsw.Это означает, что ЦП должен делать широкие накопления в памяти WC.

Если исходные данные горячие в кеше L1d или L2, потому что вы только что записали их, а местом назначения является видеопамять USWC, то с помощью rep movsw должен легко закончить во время VBI.Если он отображается как UC (это был вариант BIOS, когда WC был относительно новой функцией, по крайней мере, на платах Pentium III / ранних K8), то современный ПК с множеством ГГц, вероятно, все еще достаточно быстр.

(Кстати, repne cmpsb все еще медленный, но повторы перемещений / стоков быстро).

Кстати, даже со встроенной графикой, где «видеопамять» все еще является частью вашей обычной DRAM, это будет UC(без кэширования) или WC (без кэширования с комбинированием записи).Конечно, большая часть интерфейса VGA эмулируется в наши дни.VGA память может быть реальным кадровым буфером, используемым вашим графическим оборудованием, хотя (если он работает на голом металле, а не на DOSBOX или другом эмуляторе).

В любом случае, на современном оборудовании для низких частот, вы, вероятно, хорошопроверяйте только очищаемый бит, так как копирование выполняется так быстро по сравнению с частотой обновления, что вероятность получения разрывов практически равна нулю.Или, может быть, первый или два пикселя могут быть из старого кадра.


В DOSBOX, имитирующем настоящий старый ПК с реалистичной тактовой частотой :

@ Ped7G говорит, что rep movsw было недостаточно быстрым для копирования кадра во время VBI, если только вы не настроили DOSBOX для имитации 486 при ~ 70 МГц или скорости «динамический / макс.»

...