[Назад] [Далее]

4.5.2. Работа с SVGA-режимами

В режиме VGA 320x200 с 256 цветами для отображения видеопамяти на основное адресное пространство используется 64 000 байт, располагающихся с адреса A000h:0000h. Дальнейшее увеличение разрешения или числа цветов приводит к тому, что объем видеопамяти превышает максимальные границы сегмента в реальном режиме (65 535 байт), а затем и размер участка адресного пространства, отводимого для видеопамяти (160 Кб, от A000h:0000h до B800h:FFFFh. С адреса C800h:0000h начинается область ROM BIOS). Чтобы вывести изображение, используются два механизма — переключение банков видеопамяти для реального режима и LFB (линейный кадровый буфер) для защищенного.

Во втором случае вся видеопамять отображается на непрерывный кусок адресного пространства, но начинающегося не с адреса 0A0000h, а с какого-нибудь другого адреса, так чтобы весь образ видеопамяти, который может занимать несколько мегабайтов, отобразился в один непрерывный массив. В защищенном режиме максимальный размер сегмента составляет 4 гигабайта, поэтому никаких сложностей с адресацией этого буфера не возникает. Буфер LFB можно использовать, только если видеоадаптер поддерживает спецификацию VBE 2.0 (см. пример в главе 6.4).

В реальном режиме вывод на экран осуществляется по-прежнему копированием данных в 64-килобайтный сегмент, обычно начинающийся с адреса A000h:0000h, но эта область памяти соответствует только части экрана. Чтобы вывести изображение в другую часть экрана, требуется вызвать функцию перемещения окна (или, что то же самое, переключения банка видеопамяти), изменяющую область видеопамяти, которой соответствует сегмент A000h. Например, в режиме 640x480 с 256 цветами требуется 307 200 байт для хранения всего видеоизображения. Заполнение сегмента A000h:0000h – A000h:FFFFh приводит к закраске приблизительно 1/5 экрана, перемещение окна А на позицию 1 (или переключение на банк 1) и повторное заполнение этой же области приводит к закраске следующей 1/5 экрана, и т.д. Перемещение окна осуществляется подфункцией 05 видеофункции 4Fh или передачей управления прямо на процедуру, адрес которой можно получить, вызвав подфункцию 01, как будет показано ниже. Некоторые видеорежимы позволяют использовать сразу два таких 64-килобайтных окна, окно А и окно В, так что можно записать 128 Кб данных, не вызывая прерывания.


Стандартные графические режимы SVGA могут быть 4-, 8-, 15-, 16-, 24- и 32-битными.


4-битные режимы (16 цветов):

VGA

012h: 640x480 (64 Кб)

VESA VBE 1.0

102h: 800x600 (256 Кб)

104h: 1024x768 (192 Кб)

106h: 1280x1024 (768 Кб)


Каждый пиксель описывается одним битом, для вывода цветного изображения требуется программирование видеоадаптера на уровне портов ввода-вывода (глава 5.10.4).


8-битные режимы (256 цветов):

VGA

013h: 320x200 (64 Кб)

VBE 1.0

100h: 640x400 (256 Кб)

101h: 640x480 (320 Кб)

103h: 800x600 (512 Кб)

105h: 1024x768 (768 Кб)

107h: 1280x1024 (1,3 Мб)

VBE 2.0

120h: 1600x1200 (1,9 Мб)


Каждый пиксель описывается ровно одним байтом. Значение байта — нoмер цвета из палитры, значения цветов которой можно изменять, например вызывая подфункцию 09 видеофункции 4Fh.


15-битные режимы (32 К цветов):

VBE 1.2

10Dh: 320x200 (128 Кб)

110h: 640x480 (768 Кб)

113h: 800x600 (1 Мб)

116h: 1024x768 (1,5 Мб)

119h: 1280x1024 (2,5 Мб)

VBE 2.0

121h: 1600x1200 (3,8 Мб)


Каждый пиксель описывается ровно одним словом (16 бит), в котором биты 0 – 4 содержат значение синей компоненты цвета, биты 5 – 9 — зеленой, а биты 10 – 14 — красной. Бит 15 не используется.


16-битные режимы (64 К цветов):

VBE 1.2

10Eh: 320x200 (128 Кб)

111h: 640x480 (768 Кб)

114h: 800x600 (1 Мб)

117h: 1024x768 (1,5 Мб)

11Ah: 1280x1024 (2,5 Мб)

VBE 2.0

121h: 1600x1200 (3,8 Мб)


Так же как и в 15-битных режимах, каждый пиксель описывается ровно одним словом. Обычно биты 0 – 4 (5 бит) содержат значение синей компоненты, биты 5 – 10 (6 бит) — зеленой, а биты 11 – 15 (5 бит) — красной. В нестандартных режимах число бит, отводимое для каждого цвета, может отличаться, так что при их использовании следует вызвать подфункцию 01 видеофункции 4Fh и получить информацию о видеорежиме, включающую битовые маски и битовые смещения для цветов.


24-битные и 32-битные режимы (16 М цветов):

VBE 1.2

10Fh: 320x200 (192 Кб)

112h: 640x480 (1 Мб)

115h: 800x600 (1,4 Мб)

118h: 1024x768 (2,3 Мб)

11Bh: 1280x1024 (3,7 Мб)

VBE 2.0

122h: 1600x1200 (7,7 Мб)


В режимах с 24-битным и 32-битным цветом каждому пикселю на экране соответствуют три байта и одно двойное слово (4 байта). Если видеорежим использует модель памяти 6 (Direct Color), то младший байт (байт 0) содержит значение синего цвета, байт 1 содержит значение зеленого, байт 2 — значение красного, а байт 3 — в 32-битных режимах резервный и используется либо для выравнивания, либо содержит значение для альфа-канала. Некоторые видеорежимы могут использовать не Direct Color, a YUV (модель памяти 7) — здесь младший байт соответствует насыщенности красного, байт 1 — насыщенности синего, а байт 2 — яркости.

Видеоадаптер может поддерживать и собственные нестандартные видеорежимы. Список их номеров можно получить, вызвав подфункцию 00h, а получить информацию о режиме по его номеру — вызвав подфункцию 01h видеофуикции 4Fh. Более того, для стандартных режимов также следует вызывать подфункцию 01h, чтобы проверить реальную доступность режима (например, режим может быть в списке, но не поддерживаться из-за нехватки памяти). VBE 2.0 разрешает видеоадаптерам не поддерживать никаких стандартных режимов вообще.


INT 10h АН = 4Fh, AL = 00 — Получить общую SVGA-информацию

Ввод: AX = 4F00h
ES:DI = адрес буфера (512 байт)
Вывод: AL = 4Fh, если функция поддерживается
АН = 01, если произошла ошибка
АН = 00, если данные получены и записаны в буфер

Буфер для общей SVGA-информации:

+00h: 4 байта — будет содержать «VESA» после вызова прерывания, чтобы получить поля, начиная с 14h, здесь надо предварительно записать строку «VBE2»
+04h: слово — номер версии VBE в двоично-десятичном формате (0102h — для 1.2, 0200h — для 2.0)
+06h: 4 байта — адрес строки-идентификатора производителя
+0Ah: 4 байта — флаги:
    бит 0 — АЦП поддерживает 8-битные цветовые компоненты (см. подфункцию 08h)
    бит 1 — видеоадаптер несовместим с VGA
    бит 2 — АЦП можно программировать только при обратном ходе луча
    бит 3 — поддерживается спецификация аппаратного ускорения графики VBE/AF 1.0
    бит 4 — требуется вызов EnableDirectAccess перед использованием LFB
    бит 5 — поддерживается аппаратный указатель мыши
    бит 6 — поддерживается аппаратное отсечение
    бит 7 — поддерживается аппаратное копирование блоков
    биты 8 – 31 зарезервированы
+0Eh: 4 байта — адрес списка номеров поддерживаемых видеорежимов (массив слов, последнее слово = FFFFh, после которого обычно следует список нестандартных режимов, также заканчивающийся словом FFFFh)
+12h: слово — объем видеопамяти в 64-килобайтных блоках
+14h: слово — внутренняя версия данной реализации VBE
+16h: 4 байта — адрес строки с названием производителя
+1Ah: 4 байта — адрес строки с названием видеоадаптера
+1Eh: 4 байта — адрес строки с версией видеоадаптера
+22h: слово — версия VBE/AF (BCD, то есть 0100h для 1.0)
+24h: 4 байта — адрес списка номеров режимов, поддерживающих аппаратное ускорение (если бит поддержки VBE/AF установлен в 1)
+28h: 216 байт — зарезервировано VESA
+100h: 256 байт — зарезервировано для внутренних данных VBE. Так, например, в эту область копируются строки с названиями производителя, видеоадаптера, версии и т.д.

INT 10h АН = 4Fh, AL = 01 — Получить информацию о режиме

Ввод: AX = 4F01h
СХ = номер SVGA-режима (бит 14 соответствует использованию LFB, бит 13 — аппаратному ускорению)
ES:DI = адрес буфера для информации о режиме (256 байт)
Вывод: AL = 4Fh, если функция поддерживается
АН = 01, если произошла ошибка
АН = 00, если данные получены и записаны в буфер

Буфер для информации о SVGA-режиме:

+00h: слово — атрибуты режима:
    бит 0 — режим присутствует
    бит 1 — дополнительная информация (смещения 12h – 1Eh) присутствует (для VBE 2.0 эта информация обязательна и бит всегда установлен)
    бит 2 — поддерживается вывод текста на экран средствами BIOS
    бит 3 — режим цветной
    бит 4 — режим графический
    бит 5 — режим несовместим с VGA
    бит 6 — переключение банков не поддерживается
    бит 7 — LFB не поддерживается
    бит 8 — не определен
    бит 9 — (для VBE/AF) приложения должны вызвать EnableDirectAccess, прежде чем переключать банки
+02h: байт — атрибуты окна А:
    бит 1 — окно существует
    бит 2 — чтение из окна разрешено
    бит 3 — запись в окно разрешена
+03h: байт — атрибуты окна В
+04h: слово — гранулярность окна — число килобайтов, которому всегда кратен адрес начала окна в видеопамяти (обычно 64)
+06h: слово — размер окна в килобайтах (обычно 64)
+08h: слово — сегментный адрес окна А (обычно A000h)
+0Ah: слово — сегментный адрес окна В
+0Ch: 4 байта — адрес процедуры перемещения окна (аналог подфункции 05h, но выполняется быстрее)
+10h: слово — число целых байт в логической строке
+12h: слово — ширина в пикселях (для графики) или символах (для текста)
+14h: слово — высота в пикселях (для графики) или символах (для текста)
+16h: байт — высота символов в пикселях
+17h: байт — ширина символов в пикселях
+18h: байт — число плоскостей памяти (4 — для 16-цветных режимов, 1 — для обычных, число переключений банков, требуемое для доступа ко всем битам (4 или 8), — для модели памяти 5)
+19h: байт — число бит на пиксель
+1Ah: байт — число банков для режимов, в которых строки группируются в банки (2 — для CGA, 4 — для HGC)
+1Bh: байт — модель памяти:
00h — текст
01h — CGA-графика
02h — HGC-графика
03h — EGA-графика (16 цветов)
04h — VGA-графика (256 цветов в одной плоскости)
05h — Режим X (256 цветов в разных плоскостях)
06h — RGB (15-битные и выше)
07h — YUV
08h – 0Fh — зарезервированы VESA
10h – FFh — нестандартные модели
+1Ch: байт — размер банка в килобайтах (8 — для CGA и HGC, 0 — для остальных)
+1Dh: байт — число видеостраниц
+1Eh: байт — зарезервирован
+1Fh: байт — битовая маска красной компоненты
+20h: байт — первый бит красной компоненты
+21h: байт — битовая маска зеленой компоненты
+22h: байт — первый бит зеленой компоненты
+23h: байт — битовая маска синей компоненты
+24h: байт — первый бит синей компоненты
+25h: байт — битовая маска зарезервированной компоненты
+26h: байт — первый бит зарезервированной компоненты
+27h: байт — дополнительные флаги:
    бит 0: —поддерживается перепрограммирование цветов (подфункция 09h)
    бит 1 — приложение может использовать биты в зарезервированной компоненте
+28h: 4 байта — физический адрес начала LFB
+2Ch: 4 байта — смещение от начала LFB, указывающее на первый байт после конца участка памяти, отображающейся на экране
+30h: слово — размер памяти в LFB, не отображающейся на экране, в килобайтах
+32h: 206 байт — зарезервировано

INT 10h АН = 4FH, AL = 02 — Установить режим

Ввод: AX=4F02h
ВХ = номер режима:
    биты 0 – 6 — собственно номер режима
    бит 7 — видеопамять не очищается при установке режима, если все следующие биты — нули
    бит 8 — стандартный VBE SVGA-режим
    бит 9 — нестандартный SVGA-режим
    биты 10 – 12 — зарезервированы
    бит 13 — режим использует аппаратное ускорение
    бит 14 — режим использует LFB
    бит 15 — видеопамять не очищается при установке режима
Кроме того, специальный номер режима 81FFh соответствует доступу ко всей видеопамяти и может использоваться для сохранения ее содержимого.
Вывод: AL = 4Fh, если функция поддерживается
АН = 00, если режим установлен
АН = 01 или 02, если произошла ошибка

INT 10h АН = 4Fh, AL = 03 — Узнать номер текущего видеорежима

Ввод: АХ = 4F03h
Вывод: AL = 4Fh, если функция поддерживается
ВХ = номер режима

INT 10h АН = 4Fh AL = 05 — Перемещение окна (переключение банка видеопамяти)

Ввод: АХ = 4F03h
ВН = 00 — установить окно
ВН = 01 — считать окно
BL = 00 — окно А
BL = 01 — окно В
DX = адрес окна в видеопамяти в единицах гранулярности (номер банка), если ВН = 0
Вывод: AL = 4Fh, если функция поддерживается
DX = адрес окна в единицах гранулярности (номер банка), если ВН = 1
АН = 03, если функция была вызвана в режиме, использующем LFB

Всегда предпочтительнее переключать банки прямым дальним вызовом процедуры, адрес которой возвращается подфункцией 01h в блоке информации о видеорежиме. Все параметры передаются в процедуру точно так же, как и в подфункцию 05h, но содержимое регистров АХ и DX по возвращении не определено.


INT 10h АН = 4Fh AL = 07 — Установка начала изображения

Ввод: АХ = 4F07h
ВН = 00
BL = 00 — считать начало изображения
BL = 80h — установить начало изображения (в VBE 2.0 автоматически выполняется при следующем обратном ходе луча)
СХ = первый изображаемый пиксель в строке (для BL = 80h)
DX = первая изображаемая строка (для BL = 80h)
Вывод: AL = 4Fh, если функция поддерживается
АН = 01, если произошла ошибка
АН = 00, если функция выполнилась успешно
ВН = 00 (для BL = 00)
СХ = первый изображаемый пиксель в строке (для BL = 00)
DX = первая изображаемая строка (для BL = 00)

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

: scrolls.asm
; Изображает в разрешении 1024x768x64К окрашенный конус, который можно
; плавно перемещать по экрану стрелками вверх и вниз.
;
        .model     tiny
        .code
        .386                       ; используется команда shrd
        org        100h            ; СОМ-файл
start:
        mov        ax,4F01h        ; получить информацию о видеорежиме
        mov        cx,116h         ; 1024x768x64К
        mov        di,offset vbe_mode_buffer
        int        10h
; здесь для простоты опущена проверка наличия режима
        mov        ax,4F02h        ; установить режим
        mov        bx,116h
        int        10h
        push       word ptr [vbe_mode_buffer+8]
        pop        es              ; поместить в ES адрес начала видеопамяти
                                   ; (обычно A000h)
        cld

; вывод конуса на экран

        mov        cx,-1           ; начальное значение цвета (белый)
        mov        si,100          ; начальный радиус
        mov        bx,300          ; номер столбца
        mov        ax,200          ; номер строки
main_loop:
        inc        si                    ; увеличить радиус круга на 1
        inc        ax                    ; увеличить номер строки
        inc        bx                    ; увеличить номер столбца
        call       fast_circle           ; нарисовать круг
        sub        cx,0000100000100001b  ; изменить цвет
        cmp        si,350                ; если еще не нарисовано 250 кругов,
        jb         main_loop             ; продолжить,
        xor        сх,сх                 ; иначе: выбрать черный цвет,
        call       fast_circle           ; нарисовать последний круг

; плавное перемещение изображения по экрану с помощью функции 4F07

        xor        bx,bx           ; ВХ = 0 - установить начало экрана
        xor        dx,dx           ; номер строки = 0
                                   ; номер столбца в СХ уже ноль
main_loop_2:
        mov        ax,4F07h
        int        10h             ; переместить начало экрана
        mov        ah,7            ; считать нажатую клавишу с ожиданием, без эха
        int        21h             ; и без проверки на Ctrl-Break,
        test       al,al           ; если это обычная клавиша -
        jnz        exit_loop_2     ; завершить программу,
        int        21h             ; иначе: получить расширенный ASCII-код,
        cmp        al,50h          ; если это стрелка вниз
        je         key_down
        cmp        al,48h          ; или вверх - вызвать обработчик,
        je         key_up
exit_loop_2:                       ; иначе - завершить программу
        mov        ах,З            ; текстовый режим
        int        10h
        ret                        ; завершить СОМ-программу

key_down:                          ; обработчик нажатия стрелки вниз
        dec        dx              ; уменьшить номер строки начала экрана,
        jns        main_loop_2     ; если знак не изменился - продолжить цикл,
                                   ; иначе (если номер был 0, а стал -1) -
                                   ; увеличить номер строки
key_up:                            ; обработчик нажатия стрелки вверх
        inc        dx              ; увеличить номер строки начала экрана
        jmp        short main_loop_2

; Процедура вывода точки на экран в 16-битном видеорежиме
; Ввод: DX = номер строки, ВХ = номер столбца, ES = А000, СХ = цвет
; модифицирует АХ

putpixel16b:
        push       dx
        push       di
        хоr        di,di
        shrd       di,dx,6         ; DI = номер строки * 1024 mod 65 536
        shr        dx,5            ; DX = номер строки / 1024 * 2
        inc        dx
        cmp        dx,current_bank ; если номер банка для выводимой точки
        jne        bank_switch     ; отличается от текущего - переключить банки
switched:
        add        di,bx           ; добавить к DI номер столбца
        mov        ax,cx           ; цвет в АХ
        shl        di,1            ; DI = DI * 2, так как адресация идет в словах
        stosw                      ; вывести точку на экран
        pop        di              ; восстановить регистры
        pop        dx
        ret
bank_switch:                       ; переключение банка
        push       bx
        xor        bx,bx           ; BX = 0 -> Установить начало экрана
        mov        current_bank,dx ; сохранить новый номер текущего банка
        call       dword ptr [vbe_mode_buffer+0Ch]  ; переключить
                                                    ; банк
        pop        bx
        jmp        short switched

; Алгоритм рисования круга, используя только сложение, вычитание и сдвиги
; (упрощенный алгоритм промежуточной точки).
; Ввод: SI = радиус, СХ = цвет, АХ = номер столбца центра круга,
; ВХ = номер строки центра круга модифицирует DI, DX

fast_circle:
        push       si
        push       ax
        push       bx
        xor        di,di         ; DI - относительная Х-координата текущей точки
        dec        di            ; (SI - относительная Y-координата, начальное
        mov        ax,1          ; значение - радиус)
        sub        ax,si         ; AX - наклон (начальное значение 1-Радиус)
circle_loop:
        inc        di            ; следующий X (начальное значение - 0)
        cmp        di,si         ; цикл продолжается, пока X < Y
        ja         exit_main_loop

        pop        bx            ; BX = номер строки центра круга
        pop        dx            ; DX = номер столбца центра круга
        push       dx
        push       bx

        push       ax            ; сохранить АХ (putpixel16b его изменяет)
        add        bx,di         ; вывод восьми точек на окружности:
        add        dx,si
        call       putpixel16b   ; центр_Х + X, центр_Y + Y
        sub        dx,si
        sub        dx,si
        call       putpixel16b   ; центр_X + X, центр_Y - Y
        sub        bx,di
        sub        bx,di
        call       putpixel16b   ; центр_Х - X, центр_Y - Y
        add        dx,si
        add        dx,si
        call       putpixel16b   ; центр_Х - X, центр_Y + Y
        sub        dx,si
        add        dx,di
        add        bx,di
        add        bx,si
        call       putpixel16b   ; центр_Х + Y, центр_Y + X
        sub        dx,di
        sub        dx,di
        call       putpixel16b   ; центр_Х + Y, центр_Y - X
        sub        bx,si
        sub        bx,si
        call       putpixel16b   ; центр_Х - Y, центр_Y - X
        add        dx,di
        add        dx,di
        call       putpixel16b   ; центр_Х - Y, центр_Y + X
        pop        ax

        test       ax,ax         ; если наклон положительный
        js         slop_negative
        mov        dx,di
        sub        dx,si
        shl        dx,1
        inc        dx
        add        ax,dx         ; наклон = наклон + 2(Х - Y) + 1
        dec        si            ; Y = Y - 1
        jmp        circle_loop
slop_negative:                   ; если наклон отрицательный
        mov        dx,di
        shl        dx,1
        inc        dx
        add        ax,dx         ; наклон = наклон + 2X + 1
        jmp        circle_loop   ; и Y не изменяется
exit_main_loop:
        pop        bx
        pop        ax
        pop        si
        ret

current_bank       dw    0       ; номер текущего банка
vbe_mode_buffer:                 ; начало буфера данных о видеорежиме
        end        start

В этом примере для наглядности отсутствуют необходимые проверки на поддержку VBE (все прерывания должны возвращать 4Fh в AL), на поддержку видеорежима (атрибут видеорежима в первом байте буфера, заполняемого подфункцией 02) или на объем видеопамяти (должно быть как минимум 2 Мб) и на другие ошибки (все прерывания должны возвращать 0 в АН).

Для вывода точки на экран используется выражение типа

номер_банка = номер_строки * байт_в_строке / байт_в_банке
смещение = номер_строки * байт_в_строке MOD байт_в_банке

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

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


п»ї
"target=_blank><\/a>") //-->